private Expression LogicalExpression(Tree tree, Expression dto, IClassCache cache) { var children = new List <Graph.ITuple <Edge, Tree> >(tree.Children); if (children.Count != 3) { return(null); } var left = FilterExpression(children[0].Item2, dto, cache); var right = FilterExpression(children[2].Item2, dto, cache); var compareText = tree.Children.ToList()[1].Item2.Root.Value.Text.ToLower(); bool compare(string expected) => compareText == expected.ToLower(); if (compare("and")) { return(Expression.And(left, right)); } if (compare("or")) { return(Expression.Or(left, right)); } throw new NotImplementedException(); }
public Database(Configuration configuration) { this.connectionString = configuration.ConnectionString; if (this.connectionString == null) { throw new Exception("Configuration.ConnectionString is missing"); } if (!this.connectionString.ToLowerInvariant().Contains(FullUriKey)) { throw new Exception("Configuration.ConnectionString has no FullUri"); } this.isInMemory = this.connectionString.ToLowerInvariant().Contains(InMemoryKey); if (this.isInMemory && !this.connectionString.ToLowerInvariant().Contains(SharedCacheKey)) { throw new Exception("Configuration.ConnectionString is in memory and FullUri has no \"?cache=shared\" parameter"); } if (this.isInMemory) { this.id = Guid.NewGuid().ToString("N").ToLowerInvariant(); } else { var connectionStringBuilder = new SQLiteConnectionStringBuilder(this.connectionString); var dataSource = connectionStringBuilder.FullUri; if (dataSource.Contains(UriQueySeparator)) { dataSource = dataSource.Substring(0, dataSource.IndexOf(UriQueySeparator, StringComparison.Ordinal)); } this.id = Path.GetFileName(dataSource); } this.objectFactory = configuration.ObjectFactory; if (this.objectFactory == null) { throw new Exception("Configuration.ObjectFactory is missing"); } this.roleCache = configuration.RoleCache ?? new RoleCache(); this.classCache = configuration.ClassCache ?? new ClassCache(); this.commandTimeout = configuration.CommandTimeout ?? 30; this.isolationLevel = configuration.IsolationLevel ?? IsolationLevel.Serializable; this.autoIncrement = configuration.AutoIncrement ?? false; this.mapping = new Mapping(this); if (this.isInMemory) { this.inMemoryConnection = new SQLiteConnection(this.ConnectionString); this.inMemoryConnection.Open(); } this.idSequence = IdSequence.GetOrCreate(this); }
public Database(Configuration configuration) { this.connectionString = configuration.ConnectionString; if (this.connectionString == null) { throw new Exception("Configuration.ConnectionString is missing"); } var connectionStringBuilder = new SqlConnectionStringBuilder(this.connectionString); var applicationName = connectionStringBuilder.ApplicationName.Trim(); if (!string.IsNullOrWhiteSpace(applicationName)) { this.Id = applicationName; } else { if (!string.IsNullOrWhiteSpace(connectionStringBuilder.InitialCatalog)) { this.Id = connectionStringBuilder.InitialCatalog.ToLowerInvariant(); } else { using (this.connection = new SqlConnection(this.connectionString)) { this.connection.Open(); this.Id = this.connection.Database.ToLowerInvariant(); } } } this.objectFactory = configuration.ObjectFactory; if (this.objectFactory == null) { throw new Exception("Configuration.ObjectFactory is missing"); } if (!this.objectFactory.MetaPopulation.IsValid) { throw new ArgumentException("Domain is invalid"); } this.Mapping = new Mapping(this); this.roleCache = configuration.RoleCache ?? new RoleCache(); this.classCache = configuration.ClassCache ?? new ClassCache(); this.CommandTimeout = configuration.CommandTimeout ?? 30; this.IsolationLevel = configuration.IsolationLevel ?? IsolationLevel.Snapshot; this.SchemaName = configuration.SchemaName ?? "allors"; this.useViews = configuration.UseViews ?? true; }
public QueryParser(Parameters parameters, GraphSchema graph, IClassCache cache) { IsParsed = false; ClassProperties = graph.Vertices .Select(v => v.Value.Properties) .SelectMany(x => x).Select(x => x.Name) .Distinct(); OrderBy = new OrderByClauseParser <TRootVertex>(x => _GetTokens(x), parameters.OrderBy, graph, TermHelper.OrderByTerms); Select = new SelectClauseParser <TRootVertex>(x => _GetTokens(x), parameters.Select, graph, TermHelper.SelectTerms); Filter = new FilterClauseParser <TRootVertex>(x => _GetTokens(x), parameters.Filter, TermHelper.FilterTerms); Expand = new ExpandClauseParser <TRootVertex>(x => _GetTokens(x), parameters.Expand, graph, Select, Filter, TermHelper.ExpandTerms); _Graph = graph; Cache = cache; Parse(); }
public Expression FilterExpression(Tree tree, Expression dto, IClassCache cache) { if (tree.IsDirectPropertyAccess()) { return(Expression.PropertyOrField(dto, tree.Root.Value.Text)); } if (tree.IsPropertyAccess()) { if (cache.GetOrAdd(dto.Type).CollectionNames.Contains(tree.Root.Value.Text)) { return(Expression.Empty()); } return(FilterExpression(tree.Children.FirstOrDefault().Item2, Expression.PropertyOrField(dto, tree.Root.Value.Text), cache)); } if (tree.Root.Value.Text == TextRepresentation.ValueComparison) { return(ComparisonExpression(tree, dto, cache)); } if (tree.Root.Value.Text == TextRepresentation.LogicalComparison) { return(LogicalExpression(tree, dto, cache)); } if (tree.IsStringFunction()) { return(StringFunction(tree, dto, cache)); } if (tree.Representation == TextRepresentation.BooleanValue) { return(BoolExpression(tree)); } if (tree.Representation == TextRepresentation.NumberValue) { return(Expression.Constant(tree.Root.Value.Parsed, tree.Root.Value.Type)); } if (tree.Representation == TextRepresentation.TextValue) { return(Expression.Constant(tree.Root.Value.Text.Substring(1, tree.Root.Value.Text.Length - 2))); } throw new NotImplementedException(); }
public NoDataQuery( IQueryable <TDto> source, Parameters parameters, IClassCache cache, IEnumerable <ITuple <PathToProperty, SortDirection> > orderBy, Expression selectExpandExpression, Expression filterExpression, ParameterExpression dtoParameterExpression, QueryTree selectionTree) { Source = source; Parameters = parameters; SelectionTree = selectionTree; SelectExpandExpression = selectExpandExpression; DtoExpression = dtoParameterExpression; FilterExpression = filterExpression; OrderByPath = orderBy; Cache = cache; }
private static IEnumerable <MemberBinding> ExpansionMemberBindings(Expression dto, QueryTree tree, IClassCache cache) { var vertex = tree.Root; var classInfo = cache.Get(vertex.Value.TypeId); var outgoingEdges = tree.Children.Select(c => c.Item1); // Bind all the non-expandable types. foreach (var prop in BindingsForProperties(vertex, cache, dto)) { yield return(prop); } // navigation properties foreach (var prop in vertex.Value.Properties.Where(x => x.IsNavigationProperty)) { var propertyInfo = classInfo.NavigationProperties.First(x => x.Name == prop.Name); var navigationVertex = outgoingEdges.FirstOrDefault(x => x.Value.Name == prop.Name).To; var navigationTree = tree.Children.First(c => c.Item1.To == navigationVertex).Item2; yield return(Expression.Bind(propertyInfo, GetExpandExpression(Expression.PropertyOrField(dto, prop.Name), navigationTree, cache))); } // // collections foreach (var prop in vertex.Value.Properties.Where(x => x.IsCollection)) { var propertyInfo = classInfo.Collections.First(x => x.Name == prop.Name); if (!propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GenericTypeArguments.Length != 1) { continue; } var collectionVertex = outgoingEdges.Single(x => x.Value.Name == prop.Name).To; var navigationTree = tree.Children.First(c => c.Item1.To == collectionVertex).Item2; var collectionType = cache.GetTypeFromId(collectionVertex.Value.TypeId); var listType = typeof(List <>).MakeGenericType(collectionType); var childrenParameter = Expression.Parameter(collectionType, prop.Name); var childrenProperty = Expression.PropertyOrField(dto, prop.Name); var select = ExpressionBuilder.BuildSelectExpression(collectionType, childrenProperty, childrenParameter, GetExpandExpression(childrenParameter, navigationTree, cache)); var list = Expression.Condition( Expression.Equal(childrenProperty, Expression.Constant(null)), Expression.New(listType.GetConstructor(Array.Empty <Type>()), Array.Empty <Expression>()), Expression.New(listType.GetConstructor(new Type[] { listType }), select) ); yield return(Expression.Bind(propertyInfo, list)); } }
public static Expression GetExpandExpression(Expression dto, QueryTree tree, IClassCache cache) => BindingExpression(dto, ExpansionMemberBindings(dto, tree, cache));
// private static ICacheForever<int, List<MemberBinding>> _propertyBindingCache = new DictionaryCache<int, List<MemberBinding>>(); private static IEnumerable <MemberBinding> BindingsForProperties(QueryVertex info, IClassCache cache, Expression dto) { // var hash = (info.GetHashCode() + properties.Sum(x => x.PropertyType.GetHashCode()) + dto.GetHashCode()) % int.MaxValue; // return _propertyBindingCache.GetOrAdd(info.Value.TypeId, () => // { var result = new List <MemberBinding>(); var classInfo = cache.ClassFromTypeId(info.Value.TypeId); foreach (var prop in info.Value.Properties.Where(x => x.IsPrimitive)) { result.Add(Expression.Bind(classInfo.NonExpandableProperties.First(x => x.Name == prop.Name), Expression.PropertyOrField(dto, prop.Name))); } return(result); // }); }
public GraphTests() { cache = new ClassCache(); }
private Expression ComparisonExpression(Tree tree, Expression dto, IClassCache cache) { var children = new List <Graph.ITuple <Edge, Tree> >(tree.Children); if (children.Count != 3) { return(null); } var left = FilterExpression(children[0].Item2, dto, cache); var right = FilterExpression(children[2].Item2, dto, cache); if (left.Type != right.Type && IsNumberType(left.Type) && IsNumberType(right.Type)) { var lIndex = IndexFromType(left.Type); var rIndex = IndexFromType(right.Type); var largerIndex = Math.Max(lIndex, rIndex); if (lIndex != largerIndex) { left = Expression.Convert(left, TypeFromIndex(largerIndex)); } if (rIndex != largerIndex) { right = Expression.Convert(right, TypeFromIndex(largerIndex)); } } Expression doComparison() { var compareText = tree.Children.ToList()[1].Item2.Root.Value.Text.ToLower(); bool Compare(string expected) => compareText == expected.ToLower(); // eq, ne, gt, ge, lt ,le if (Compare("eq")) { return(Expression.Equal(left, right)); } else if (Compare("ne")) { return(Expression.NotEqual(left, right)); } else if (Compare("gt")) { return(Expression.GreaterThan(left, right)); } else if (Compare("ge")) { return(Expression.GreaterThanOrEqual(left, right)); } else if (Compare("lt")) { return(Expression.LessThan(left, right)); } else if (Compare("le")) { return(Expression.LessThanOrEqual(left, right)); } throw new NotImplementedException(); } Expression IsChildPropertyAccessNull(Tree child, Expression parentClass) { if (child.IsPropertyAccess()) { Expression conditional(Expression propertyExpression) { var nullExpr = Expression.Constant(null); if (propertyExpression.Type.IsValueType) { return(null); } return(Expression.NotEqual(propertyExpression, nullExpr)); } if (!child.IsDirectPropertyAccess()) { var subPropertyAccessCheck = IsChildPropertyAccessNull(child.Children.First().Item2, Expression.PropertyOrField(parentClass, child.Root.Value.Text)); if (subPropertyAccessCheck is null) { return(conditional(parentClass)); } return(Expression.AndAlso(conditional(parentClass), subPropertyAccessCheck)); } else { return(conditional(parentClass)); } } return(null); } var leftNullCheck = IsChildPropertyAccessNull(children[0].Item2, dto); var rightNullCheck = IsChildPropertyAccessNull(children[1].Item2, dto); if (leftNullCheck == null && rightNullCheck == null) { return(doComparison()); } if (leftNullCheck != null && rightNullCheck == null) { return(Expression.AndAlso(leftNullCheck, doComparison())); } if (leftNullCheck == null && rightNullCheck != null) { return(Expression.AndAlso(rightNullCheck, doComparison())); } return(Expression.AndAlso(Expression.AndAlso(leftNullCheck, rightNullCheck), doComparison())); }
private Expression StringFunction(Tree tree, Expression dto, IClassCache cache) { var strFunction = tree.GetStringFunction(); if (strFunction == TextRepresentation.StrLength) { // eval child expr var childExpression = FilterExpression(tree.Children.First().Item2, dto, cache); // fail if type isn't a string if (childExpression.Type != typeof(string)) { throw new ArgumentException("Tried to get length of non string property."); } return(Expression.Property(childExpression, nameof(string.Length))); } if (strFunction == TextRepresentation.StrToLower || strFunction == TextRepresentation.StrToUpper || strFunction == TextRepresentation.StrTrim) { // eval child expr var child1Expression = FilterExpression(tree.Children.First().Item2, dto, cache); // fail if type isn't a string if (child1Expression.Type != typeof(string)) { throw new ArgumentException("Can't check function endswith with argument of a non-string type."); } var methodName = ""; if (strFunction == TextRepresentation.StrToUpper) { methodName = nameof(string.ToUpper); } else if (strFunction == TextRepresentation.StrToLower) { methodName = nameof(string.ToLower); } else if (strFunction == TextRepresentation.StrTrim) { methodName = nameof(string.Trim); } var method = typeof(string).GetMethod(methodName, Array.Empty <Type>()); return(Expression.Call(child1Expression, method)); } if (strFunction == TextRepresentation.StrEndsWith || strFunction == TextRepresentation.StrStartsWith || strFunction == TextRepresentation.StrIndexOf || strFunction == TextRepresentation.StrContains) { // eval child expr var child1Expression = FilterExpression(tree.Children.First().Item2, dto, cache); var child2Expression = FilterExpression(tree.Children.Last().Item2, dto, cache); // fail if types aren't a string if (child1Expression.Type != typeof(string) || child2Expression.Type != typeof(string)) { throw new ArgumentException("Can't check function endswith with argument of a non-string type."); } var methodName = ""; if (strFunction == TextRepresentation.StrEndsWith) { methodName = nameof(string.EndsWith); } else if (strFunction == TextRepresentation.StrStartsWith) { methodName = nameof(string.StartsWith); } else if (strFunction == TextRepresentation.StrIndexOf) { methodName = nameof(string.IndexOf); } else if (strFunction == TextRepresentation.StrContains) { methodName = nameof(string.Contains); } var method = typeof(string).GetMethod(methodName, new[] { typeof(string) }); return(Expression.Call(child1Expression, method, child2Expression)); } if (strFunction == TextRepresentation.StrReplace) { var childList = tree.Children.ToList(); // eval child expr var child1Expression = FilterExpression(childList[0].Item2, dto, cache); var child2Expression = FilterExpression(childList[1].Item2, dto, cache); var child3Expression = FilterExpression(childList[2].Item2, dto, cache); // fail if types aren't a string if (child1Expression.Type != typeof(string) || child2Expression.Type != typeof(string) || child3Expression.Type != typeof(string)) { throw new ArgumentException("Can't check function endswith with argument of a non-string type."); } var methodName = nameof(string.Replace); var method = typeof(string).GetMethod(methodName, new[] { typeof(string), typeof(string) }); return(Expression.Call(child1Expression, method, child2Expression, child3Expression)); } if (strFunction == TextRepresentation.StrConcat) { var childList = tree.Children.ToList(); // eval child expr var child1Expression = FilterExpression(childList[0].Item2, dto, cache); var child2Expression = FilterExpression(childList[1].Item2, dto, cache); // fail if types aren't a string if (child1Expression.Type != typeof(string) || child2Expression.Type != typeof(string)) { throw new ArgumentException("Can't check function endswith with argument of a non-string type."); } string methodName = null; if (strFunction == TextRepresentation.StrConcat) { methodName = nameof(string.Concat); } var method = typeof(string).GetMethod(methodName, new[] { typeof(string), typeof(string) }); return(Expression.Call(method, child1Expression, child2Expression)); } if (strFunction == TextRepresentation.StrSubString) { var childList = tree.Children.ToList(); // eval child expr var child1Expression = FilterExpression(childList[0].Item2, dto, cache); var integerArgs = new List <Expression>(childList.Count - 1); // if (childList.Count == 2) // integerArgs.Add(Expression.Constant(0, typeof(int))); for (var i = 1; i < childList.Count; ++i) { integerArgs.Add(Expression.Convert(FilterExpression(childList[i].Item2, dto, cache), typeof(int))); } // fail if types aren't a string if (child1Expression.Type != typeof(string)) { throw new ArgumentException("Can't check function endswith with argument of a non-string type."); } if (!integerArgs.All(x => x.Type == typeof(int) || x.Type == typeof(long))) { throw new ArgumentException("Argument not an integer for substring function."); } var method = typeof(string).GetMethod(nameof(string.Substring), integerArgs.Select(x => x.Type).ToArray()); return(Expression.Call(child1Expression, method, integerArgs)); } throw new NotImplementedException("String function is not implemented: " + strFunction); }
private static GraphSchema CreateFromGeneric <TDto>(IClassCache cache) { var vertices = new List <StatefulVertex <ClassInfo> >(); var edges = new List <Edge>(); var types = new HashSet <Type>(); // Helper funcs // get the class info from type via the cache. ClassInfoUtility GetClassInfoFromType(Type t) { var hash = t.GetHashCode(); if (cache.HasKey(hash)) { return(cache.Get(hash)); } return(cache.GetOrAdd(t)); } bool VerticesContainType(Type type) => vertices.Any(v => v.Vertex.Value.TypeId == type.GetHashCode()); StatefulVertex <ClassInfo> GetOrAddVertex(Type type) { StatefulVertex <ClassInfo> vertex = null; if (VerticesContainType(type)) { vertex = vertices.First(v => v.Vertex.Value.TypeId == type.GetHashCode()); } else { vertex = new StatefulVertex <ClassInfo>(new Vertex(new ClassInfo(GetClassInfoFromType(type))), type); vertices.Add(vertex); types.Add(type); } return(vertex); } // initialize root. GetOrAddVertex(typeof(TDto)); while (vertices.Any(v => v.Color != StatefulVertexStateType.Discovered)) { var vertex = vertices.First(v => v.Color == StatefulVertexStateType.UnReached); vertex.Color = StatefulVertexStateType.Identified; var classInfo = GetClassInfoFromType(vertex.Type); var tentativeConnectionToType = new List <Edge>(); void EstablishConnection(Type connectionToType, Property property) { var toVertex = GetOrAddVertex(connectionToType); var edge = new Edge(vertex.Vertex as Vertex, toVertex.Vertex as Vertex, property); if (!edges.Contains(edge)) { edges.Add(edge); } } foreach (var childNavigationProperty in vertex.Vertex.Value.Properties.Where(p => p.IsNavigationProperty)) { var type = classInfo.NavigationProperties.FirstOrDefault(x => x.Name == childNavigationProperty.Name)?.PropertyType; if (type is null) { continue; } EstablishConnection(type, childNavigationProperty); } foreach (var childCollection in vertex.Vertex.Value.Properties.Where(p => p.IsCollection)) { var type = classInfo.Collections.FirstOrDefault(x => x.Name == childCollection.Name)?.PropertyType.GetGenericArguments()[0]; if (type is null) { continue; } EstablishConnection(type, childCollection); } vertex.Color = StatefulVertexStateType.Discovered; } return(new GraphSchema(vertices.Select(v => v.Vertex as Vertex), edges)); }
public CacheAndGraphFixture() { cache = new ClassCache(); graph = GraphSchema.Cache <TDto> .Graph; }
public Database(Configuration configuration) { this.connectionString = configuration.ConnectionString; if (this.connectionString == null) { throw new Exception("Configuration.ConnectionString is missing"); } var connectionStringBuilder = new SqlConnectionStringBuilder(this.connectionString); var applicationName = connectionStringBuilder.ApplicationName.Trim(); if (!string.IsNullOrWhiteSpace(applicationName)) { this.id = applicationName; } else { if (!string.IsNullOrWhiteSpace(connectionStringBuilder.InitialCatalog)) { this.id = connectionStringBuilder.InitialCatalog.ToLowerInvariant(); } else { using (this.connection = new SqlConnection(this.connectionString)) { this.connection.Open(); this.id = this.connection.Database.ToLowerInvariant(); } } } this.objectFactory = configuration.ObjectFactory; if (this.objectFactory == null) { throw new Exception("Configuration.ObjectFactory is missing"); } if (!this.objectFactory.MetaPopulation.IsValid) { throw new ArgumentException("Domain is invalid"); } this.objectIds = configuration.ObjectIds ?? new ObjectIdsInteger(); this.roleCache = configuration.RoleCache ?? new RoleCache(); this.classCache = configuration.ClassCache ?? new ClassCache(); this.commandTimeout = configuration.CommandTimeout ?? 30; this.isolationLevel = configuration.IsolationLevel ?? IsolationLevel.Snapshot; this.schemaName = configuration.SchemaName ?? "allors"; this.useViews = configuration.UseViews ?? true; if (this.ObjectIds is ObjectIdsInteger) { this.mapping = new MappingInteger(this); } else if (this.ObjectIds is ObjectIdsLong) { this.mapping = new MappingLong(this); } else { throw new NotSupportedException("ObjectIds of type " + this.ObjectIds.GetType() + " are not supported."); } }