예제 #1
0
        internal BlBinaryExpression ApplySoftDeleteFilterIfApplicable(bool includeDeleted, BlBinaryExpression filter, BlsPawn pawn)
        {
            string           containerName  = Graph.GetStorageContainerNameForPawn(pawn);
            BlGraphContainer container      = Graph.CompiledCollections.FirstOrDefault(c => c.StorageContainerName == containerName);
            BlContainerProp  softDeleteProp = container?.Properties.FirstOrDefault(prop => prop.IsSoftDeleteProp);

            if (softDeleteProp == null)
            {
                return(filter);
            }

            var softDeleteClause = new BlBinaryExpression
            {
                PropName = softDeleteProp.Name, Operator = BlOperator.Eq, Value = includeDeleted
            };

            if (filter == null)
            {
                return(softDeleteClause);
            }

            var newRoot = new BlBinaryExpression
            {
                Left = filter, Operator = BlOperator.And, Right = softDeleteClause
            };

            return(newRoot);
        }
예제 #2
0
        /// <summary>
        /// Use this method to find pawns based on their properties. If you do not provide any
        /// filter predicates, the method will return all pawns of the specified type.
        /// </summary>
        /// <param name="includeSoftDeleted">Also retrieve soft deleted pawns if set to true; false by default</param>
        /// <param name="filter">Boolean expression specifying the filtering conditions</param>
        /// <param name="sortProperty">Property of the pawn to use for sorting</param>
        /// <param name="sortDir">Ascending or Descending</param>
        /// <param name="batchSize">Number of records to return in the <see cref="BLS.StorageCursor"/> class></param>
        /// <typeparam name="TPawn">Type of the pawn</typeparam>
        /// <returns>Storage Cursor containing the resulting collection of pawns</returns>
        /// <exception cref="NotImplementedException"></exception>
        public StorageCursor <TPawn> Find <TPawn>(
            Expression <Func <TPawn, bool> > filter = null,
            Expression <Func <TPawn, IComparable> > sortProperty = null,
            Sort sortDir            = Sort.Asc,
            bool includeSoftDeleted = false,
            int batchSize           = 200) where TPawn : BlsPawn, new()
        {
            string             container        = Graph.GetStorageContainerNameForPawn(new TPawn());
            BlBinaryExpression filterExpression = ResolveFilterExpression(filter);

            filterExpression = ApplySoftDeleteFilterIfApplicable(includeSoftDeleted, filterExpression, new TPawn());
            string sortProp = ResolveSortExpression(sortProperty);

            var cursor = StorageProvider.FindInContainer <TPawn>(container, filterExpression, sortProp, sortDir.ToString(), batchSize);

            var additions = ToAddBuffer
                            .Where(p => p.GetType() == typeof(TPawn))
                            .Cast <TPawn>();

            var updates = ToUpdate
                          .Where(p => p.GetType() == typeof(TPawn))
                          .Select(p => (TPawn)p);


            if (filter == null)
            {
                cursor.AttachInMemoryPawns(additions.ToList()).AttachInMemoryPawns(updates.ToList());
            }

            return(cursor);
        }
예제 #3
0
        /// <summary>
        /// Call the method to get number of related pawns. The result will include both in-storage and in-memory pawns
        /// </summary>
        /// <param name="includeSotDeleted">If set to true, the method ignores soft-delete flag if one is available on the
        /// pawn model. Set to false by default</param>
        /// <returns>Number of related pawns</returns>
        /// <exception cref="NotImplementedException"></exception>
        public int GetCount(bool includeSotDeleted = false)
        {
            BlBinaryExpression filter = SourcePawn.SystemRef
                                        .ApplySoftDeleteFilterIfApplicable(includeSotDeleted, null, new T());

            string containerName = SourcePawn.SystemRef.Graph.GetStorageContainerNameForPawn(new T());

            return(SourcePawn.SystemRef.StorageProvider.GetContainerCount(containerName, filter));
        }
예제 #4
0
        // recursive method to resolve AND/OR binary filter expressions
        private BlBinaryExpression ResolveBinaryFilterExpression(BinaryExpression expression,
                                                                 BlBinaryExpression newExpression)
        {
            newExpression.Left  = new BlBinaryExpression();
            newExpression.Right = new BlBinaryExpression();

            switch (expression.NodeType)
            {
            case ExpressionType.AndAlso:
            {
                newExpression.Operator = BlOperator.And;
                break;
            }

            case ExpressionType.OrElse:
            {
                newExpression.Operator = BlOperator.Or;
                break;
            }
            }

            if (expression.Left.GetType().Name == MethodBinaryExpression)
            {
                newExpression.Left = ResolveComparisonFilterExpression(expression.Left as BinaryExpression);
            }
            else
            {
                newExpression.Left =
                    ResolveBinaryFilterExpression(expression.Left as BinaryExpression, newExpression.Left);
            }

            if (expression.Right.GetType().Name == MethodBinaryExpression)
            {
                newExpression.Right = ResolveComparisonFilterExpression(expression.Right as BinaryExpression);
            }
            else
            {
                newExpression.Right =
                    ResolveBinaryFilterExpression(expression.Right as BinaryExpression, newExpression.Right);
            }

            return(newExpression);
        }
예제 #5
0
        /// <summary>
        /// Call the method to search for pawns based on the search term, optionally specifying
        /// any additional filters and sort
        /// </summary>
        /// <param name="searchTerm">The term to search</param>
        /// <param name="filter">Boolean expression specifying any additional filter conditions</param>
        /// <param name="includeSoftDeleted">Also retrieve soft deleted pawns if set to true; false by default</param>
        /// <param name="sortProperty">Property of the pawn to use for sorting</param>
        /// <param name="sortDir">Ascending or Descending</param>
        /// <param name="batchSize">Number of records to return in the <see cref="BLS.StorageCursor"/> class</param>
        /// <param name="searchProperties">List of property expressions to apply the search on. Only properties
        /// marked with the <see cref="BLS.Functional.FullTextSearchable"/> attribute are allowed in the list of</param>
        /// <typeparam name="TPawn">Type of the pawn</typeparam>
        /// <returns>Storage Cursor containing the resulting collection of pawns</returns>
        /// <exception cref="NotImplementedException"></exception>
        public StorageCursor <TPawn> Search <TPawn>(
            string searchTerm,
            Expression <Func <TPawn, string[]> > searchProperties,
            Expression <Func <TPawn, bool> > filter = null,
            Expression <Func <TPawn, IComparable> > sortProperty = null,
            Sort sortDir            = Sort.Asc,
            bool includeSoftDeleted = false,
            int batchSize           = 200) where TPawn : BlsPawn, new()
        {
            var container = Graph.GetStorageContainerNameForPawn(new TPawn());
            BlBinaryExpression filterExpression = ResolveFilterExpression(filter);

            filterExpression = ApplySoftDeleteFilterIfApplicable(includeSoftDeleted, filterExpression, new TPawn());
            string sortProp = ResolveSortExpression(sortProperty);

            return(StorageProvider.SearchInContainer <TPawn>(
                       container,
                       ResolveSearchProperties(searchProperties),
                       searchTerm,
                       filterExpression,
                       sortProp,
                       sortDir.ToString(),
                       batchSize));
        }
예제 #6
0
        /// <summary>
        /// Use this method to retrieve related objects of the certain <typeparam name="T"></typeparam> type. The method
        /// returns a cursor which contains pawns in storage as well as pawns currently sitting in the BLS memory
        /// </summary>
        /// <param name="filter">Optional filter to apply to the result set; the filter will be applied to both the im-memory
        /// and in-storage data</param>
        /// <param name="sortDir"></param>
        /// <param name="includeSoftDeleted">If set to true, the method ignores soft-delete flag if one is available on the
        /// pawn model. Set to false by default</param>
        /// <param name="batchSize">Controls the size of the batch of each incremental retrieval of pawns from storage. Defaults to 200 objects</param>
        /// <param name="sortProperty"></param>
        /// <returns>Cursor containing the result set</returns>
        /// <exception cref="InvalidOperationException"></exception>
        public StorageCursor <T> Find(
            Expression <Func <T, bool> > filter = null,
            Expression <Func <T, IComparable> > sortProperty = null,
            Sort sortDir            = Sort.Asc,
            bool includeSoftDeleted = false,
            int batchSize           = 200)
        {
            Connection[] connections = SourcePawn.SystemRef.ToConnect
                                       .Where(c => c.From == SourcePawn)
                                       .ToArray();

            BlGraphContainer container = SourcePawn.SystemRef.Graph.CompiledCollections
                                         .FirstOrDefault(c => c.BlContainerName == typeof(T).Name);

            if (container == null)
            {
                throw new InvalidOperationException("collection not found");
            }

            string id            = SourcePawn.GetId();
            string relationName  = SourcePawn.SystemRef.Graph.GetStorageRelationName(this);
            string containerName = SourcePawn.SystemRef.Graph.GetStorageContainerNameForPawn(SourcePawn);

            if (filter == null)
            {
                var filterExpression = SourcePawn.SystemRef
                                       .ApplySoftDeleteFilterIfApplicable(includeSoftDeleted, null, new T());

                List <T> connectedPawns = connections.Select(c => (T)c.To).ToList();

                // if there is no id, the pawn has not been saved yet so there only return in-memory relations
                if (string.IsNullOrEmpty(id))
                {
                    return(new StorageCursor <T>().AttachInMemoryPawns(connectedPawns).InjectBls(SourcePawn.SystemRef));
                }

                // otherwise, also check the storage

                string sort = SourcePawn.SystemRef.ResolveSortExpression(sortProperty);

                var cursorFromStorage =
                    SourcePawn.SystemRef.StorageProvider.GetByRelation <T>(id, relationName, containerName, filterExpression, sort, sortDir, batchSize);
                return(cursorFromStorage.AttachInMemoryPawns(connectedPawns).InjectBls(SourcePawn.SystemRef));
            }

            // the rest of the code assumes the filter is not null
            if (string.IsNullOrEmpty(id))
            {
                List <T> foundRelations = connections.Select(c => (T)c.To).ToList();
                List <T> connectedPawns = foundRelations.Where(filter.Compile()).ToList();
                return(new StorageCursor <T>().AttachInMemoryPawns(connectedPawns).InjectBls(SourcePawn.SystemRef));
            }
            else
            {
                List <T>           foundRelations          = connections.Select(c => (T)c.To).ToList();
                List <T>           connectedPawns          = foundRelations.Where(filter.Compile()).ToList();
                BlBinaryExpression storageFilterExpression = SourcePawn.SystemRef.ResolveFilterExpression(filter);

                storageFilterExpression = SourcePawn.SystemRef
                                          .ApplySoftDeleteFilterIfApplicable(includeSoftDeleted, storageFilterExpression, new T());

                string sort = SourcePawn.SystemRef.ResolveSortExpression(sortProperty);

                StorageCursor <T> cursorFromStorage =
                    SourcePawn.SystemRef.StorageProvider.GetByRelation <T>(id, relationName, containerName, storageFilterExpression, sort, sortDir, batchSize);
                return(cursorFromStorage.AttachInMemoryPawns(connectedPawns).InjectBls(SourcePawn.SystemRef));
            }
        }
예제 #7
0
        // method to resolve final comparison (==, !=, >, etc.) expressions in the filter expression
        private BlBinaryExpression ResolveComparisonFilterExpression(BinaryExpression expression)
        {
            if (expression.Left.GetType().Name != PropertyExpressionType)
            {
                throw new IncorrectFilterArgumentStructureError(
                          $"Left operand of the filter expression has to be a property accessor . You provided {expression.Left.GetType().Name}");
            }

            BlBinaryExpression resultExpression = new BlBinaryExpression();

            switch (expression.NodeType)
            {
            case ExpressionType.Equal:
            {
                resultExpression.Operator = BlOperator.Eq;
                break;
            }

            case ExpressionType.NotEqual:
            {
                resultExpression.Operator = BlOperator.NotEq;
                break;
            }

            case ExpressionType.GreaterThan:
            {
                resultExpression.Operator = BlOperator.Grt;
                break;
            }

            case ExpressionType.GreaterThanOrEqual:
            {
                resultExpression.Operator = BlOperator.GrtOrEq;
                break;
            }

            case ExpressionType.LessThan:
            {
                resultExpression.Operator = BlOperator.Ls;
                break;
            }

            case ExpressionType.LessThanOrEqual:
            {
                resultExpression.Operator = BlOperator.LsOrEq;
                break;
            }

            default:
            {
                throw new NotSupportedException("incorrect binary operator");
            }
            }

            if (expression.Left is MemberExpression propAccessor)
            {
                resultExpression.PropName = propAccessor.Member.Name;
            }

            resultExpression.Value  = Expression.Lambda(expression.Right).Compile().DynamicInvoke();
            resultExpression.IsLeaf = true;

            return(resultExpression);
        }