Example #1
0
        /// <summary>
        /// Adds a <see cref="SearchCondition"/> to the collection for a <see cref="MFDataType.MFDatatypeDate"/>
        /// or <see cref="MFDataType.MFDatatypeTimestamp"/> property definition.
        /// This method searches solely by the year and month components in the property value , equivalent to using
        /// a <see cref="DataFunctionCall" /> set to <see cref="DataFunctionCall.SetDataYearAndMonth" />.
        /// </summary>
        /// <param name="searchBuilder">The <see cref="MFSearchBuilder"/> to add the condition to.</param>
        /// <param name="propertyDef">The ID of the property to search by.</param>
        /// <param name="year">The four-digit year to search by.</param>
        /// <param name="month">The 1-based number of the month to search by (1 = January, 12 = December).</param>
        /// <param name="conditionType">What type of search to execute (defaults to <see cref="MFConditionType.MFConditionTypeEqual"/>).</param>
        /// <param name="parentChildBehavior">Whether to accept matches to parent/child values as well (defaults to <see cref="MFParentChildBehavior.MFParentChildBehaviorNone"/>).</param>
        /// <param name="indirectionLevels">The indirection levels (from the search object) to access the property to match.</param>
        /// <returns>The <paramref name="searchBuilder"/> provided, for chaining.</returns>
        public static MFSearchBuilder YearAndMonth
        (
            this MFSearchBuilder searchBuilder,
            int propertyDef,
            int year,
            int month,
            MFConditionType conditionType              = MFConditionType.MFConditionTypeEqual,
            MFParentChildBehavior parentChildBehavior  = MFParentChildBehavior.MFParentChildBehaviorNone,
            PropertyDefOrObjectTypes indirectionLevels = null
        )
        {
            // Sanity.
            if (null == searchBuilder)
            {
                throw new ArgumentNullException(nameof(searchBuilder));
            }
            if (0 > propertyDef)
            {
                throw new ArgumentOutOfRangeException(nameof(propertyDef), "Property Ids must be greater than -1; ensure that your property alias was resolved.");
            }
            if (month < 1 || month > 12)
            {
                throw new ArgumentOutOfRangeException(nameof(month), "The month number must be between 1 and 12 inclusive.");
            }
            if (year < 1000 || year > 9999)
            {
                throw new ArgumentOutOfRangeException(nameof(year), "The year must be four digits.");
            }

            // What is the type of this property?
            var dataType = searchBuilder.Vault.PropertyDefOperations.GetPropertyDef(propertyDef).DataType;

            // What is the data type of the property?
            DataFunctionCall dataFunctionCall;

            switch (dataType)
            {
            case MFDataType.MFDatatypeTimestamp:
            case MFDataType.MFDatatypeDate:

                // Timestamps and dates should be converted to text using a data function call.
                dataFunctionCall = new DataFunctionCall();
                dataFunctionCall.SetDataYearAndMonth();

                break;

            default:
                throw new ArgumentException($"Property {propertyDef} is not a date or timestamp property.", nameof(propertyDef));
            }

            // Use the property method.
            return(searchBuilder.Property
                   (
                       propertyDef,
                       $"{year}-{month:00}",
                       conditionType,
                       parentChildBehavior,
                       indirectionLevels,
                       dataFunctionCall
                   ));
        }
Example #2
0
        /// <summary>
        /// Adds a property value search condition to the collection.
        /// </summary>
        /// <param name="searchBuilder">The <see cref="MFSearchBuilder"/> to add the condition to.</param>
        /// <param name="propertyDef">The property to search by.</param>
        /// <param name="dataType">The data type of the property definition (not checked).</param>
        /// <param name="value">The value to search for.</param>
        /// <param name="conditionType">What type of search to execute.</param>
        /// <param name="parentChildBehavior">Whether to accept matches to parent/child values as well.</param>
        /// <param name="dataFunctionCall">An expression for modifying how the results of matches are evaluated.</param>
        /// <param name="indirectionLevels">The indirection levels (from the search object) to access the property to match.</param>
        /// <returns></returns>
        private static MFSearchBuilder AddPropertyValueSearchCondition
        (
            this MFSearchBuilder searchBuilder,
            int propertyDef,
            MFDataType dataType,
            object value,
            MFConditionType conditionType,
            MFParentChildBehavior parentChildBehavior,
            PropertyDefOrObjectTypes indirectionLevels,
            DataFunctionCall dataFunctionCall
        )
        {
            // Sanity.
            if (null == searchBuilder)
            {
                throw new ArgumentNullException(nameof(searchBuilder));
            }

            // Create the search condition.
            var searchCondition = new SearchCondition
            {
                ConditionType = conditionType
            };

            // Set up the property value expression.
            searchCondition.Expression.SetPropertyValueExpression
            (
                propertyDef,
                parentChildBehavior,
                dataFunctionCall
            );

            // If we have any indirection levels then use them.
            if (null != indirectionLevels)
            {
                // If any indirection level points at a value list then it will except.
                // Show a nicer error message here.
                foreach (PropertyDefOrObjectType indirectionLevel in indirectionLevels)
                {
                    var objectTypeId = indirectionLevel.ID;
                    if (indirectionLevel.PropertyDef)
                    {
                        // If it's a property def then find the object type.
                        PropertyDef indirectionLevelPropertyDef;
                        try
                        {
                            indirectionLevelPropertyDef = searchBuilder
                                                          .Vault
                                                          .PropertyDefOperations
                                                          .GetPropertyDef(indirectionLevel.ID);
                        }
                        catch
                        {
                            indirectionLevelPropertyDef = null;
                        }

                        // Does it exist?
                        if (null == indirectionLevelPropertyDef)
                        {
                            throw new ArgumentException($"An indirection level references a property definition with ID {indirectionLevel.ID}, but this property definition could not be found.", nameof(indirectionLevel));
                        }

                        // Is it a list-based one?
                        if (false == indirectionLevelPropertyDef.BasedOnValueList)
                        {
                            throw new ArgumentException($"The indirection level for property {indirectionLevel.ID} does not reference a lookup-style property definition.", nameof(indirectionLevel));
                        }

                        // Record the object type id.
                        objectTypeId = indirectionLevelPropertyDef.ValueList;
                    }

                    // Is it an object type (fine) or a value list (not fine)?
                    {
                        ObjType indirectionLevelObjectType;
                        try
                        {
                            indirectionLevelObjectType = searchBuilder
                                                         .Vault
                                                         .ValueListOperations
                                                         .GetValueList(objectTypeId);
                        }
                        catch
                        {
                            indirectionLevelObjectType = null;
                        }

                        // Does it exist?
                        if (null == indirectionLevelObjectType)
                        {
                            throw new ArgumentException($"An indirection level references a value list with ID {objectTypeId}, but this value list could not be found.", nameof(indirectionLevel));
                        }

                        // If it's not a real object type then throw.
                        if (false == indirectionLevelObjectType.RealObjectType)
                        {
                            throw new ArgumentException($"An indirection level references an value list with ID {objectTypeId}, but this list does not refer to an object type (cannot be used with value lists).", nameof(indirectionLevel));
                        }
                    }
                }

                // Set the indirection levels.
                searchCondition.Expression.IndirectionLevels
                    = indirectionLevels;
            }

            // Was the value null?
            if (null == value)
            {
                searchCondition.TypedValue.SetValueToNULL(dataType);
            }
            else
            {
                searchCondition.TypedValue.SetValue(dataType, value);
            }

            // Add the search condition to the collection.
            searchBuilder.Conditions.Add(-1, searchCondition);

            // Return the search builder for chaining.
            return(searchBuilder);
        }
        /// <summary>
        /// Adds a <see cref="SearchCondition"/> to the collection for a <see cref="MFDataType.MFDatatypeInteger"/>,
        /// <see cref="MFDataType.MFDatatypeInteger64"/> or <see cref="MFDataType.MFDatatypeFloating"/> property definition.
        /// </summary>
        /// <param name="searchBuilder">The <see cref="MFSearchBuilder"/> to add the condition to.</param>
        /// <param name="propertyDef">The ID of the property to search by.</param>
        /// <param name="value">The value to search for.</param>
        /// <param name="conditionType">What type of search to execute (defaults to <see cref="MFConditionType.MFConditionTypeEqual"/>).</param>
        /// <param name="parentChildBehavior">Whether to accept matches to parent/child values as well (defaults to <see cref="MFParentChildBehavior.MFParentChildBehaviorNone"/>).</param>
        /// <param name="dataFunctionCall">An expression for modifying how the results of matches are evaluated (defaults to null).</param>
        /// <param name="indirectionLevels">The indirection levels (from the search object) to access the property to match.</param>
        /// <returns>The <paramref name="searchBuilder"/> provided, for chaining.</returns>
        public static MFSearchBuilder Property
        (
            this MFSearchBuilder searchBuilder,
            int propertyDef,
            int?value,
            MFConditionType conditionType              = MFConditionType.MFConditionTypeEqual,
            MFParentChildBehavior parentChildBehavior  = MFParentChildBehavior.MFParentChildBehaviorNone,
            PropertyDefOrObjectTypes indirectionLevels = null,
            DataFunctionCall dataFunctionCall          = null
        )
        {
            // Sanity.
            if (null == searchBuilder)
            {
                throw new ArgumentNullException(nameof(searchBuilder));
            }
            if (0 > propertyDef)
            {
                throw new ArgumentOutOfRangeException(nameof(propertyDef), "Property Ids must be greater than -1; ensure that your property alias was resolved.");
            }

            // What is the type of this property?
            var dataType = searchBuilder.Vault.PropertyDefOperations.GetPropertyDef(propertyDef).DataType;

            // Do we need to change the data type for the data function call?
            if (dataFunctionCall != null)
            {
                switch (dataFunctionCall.DataFunction)
                {
                case MFDataFunction.MFDataFunctionDaysFrom:
                case MFDataFunction.MFDataFunctionDaysTo:
                case MFDataFunction.MFDataFunctionYear:
                {
                    // If it's a timestamp then convert to integer.
                    if (dataType == MFDataType.MFDatatypeDate ||
                        dataType == MFDataType.MFDatatypeTimestamp)
                    {
                        dataType = MFDataType.MFDatatypeInteger;
                    }

                    // Ensure value has a value.
                    if (null == value)
                    {
                        throw new ArgumentException($"value cannot be null.", nameof(value));
                    }

                    // If it's a year then it should be four-digits.
                    if (dataFunctionCall.DataFunction == MFDataFunction.MFDataFunctionYear &&
                        (value < 1000 || value > 9999))
                    {
                        throw new ArgumentException($"The year must be four digits.", nameof(value));
                    }

                    break;
                }
                }
            }

            // If it is not the right data type then throw.
            if (dataType != MFDataType.MFDatatypeInteger &&
                dataType != MFDataType.MFDatatypeInteger64 &&
                dataType != MFDataType.MFDatatypeFloating &&
                dataType != MFDataType.MFDatatypeLookup &&
                dataType != MFDataType.MFDatatypeMultiSelectLookup)
            {
                throw new ArgumentException($"Property {propertyDef} is not an integer, long, real, lookup or multi-select lookup property.", nameof(propertyDef));
            }

            // Add the search condition.
            return(searchBuilder.AddPropertyValueSearchCondition
                   (
                       propertyDef,
                       dataType,
                       value,
                       conditionType,
                       parentChildBehavior,
                       indirectionLevels,
                       dataFunctionCall
                   ));
        }
        /// <summary>
        /// Runs a method for each segment in the vault.
        /// </summary>
        /// <param name="builder">Search Builder to use for queries.</param>
        /// <param name="func">Method to be executed for each segment, takes a vault and search conditions and returns count.</param>
        /// <param name="startSegment">The (zero-based) index of the segment to start at.</param>
        /// <param name="segmentLimit">The number of total segments to process. See <see cref="DefaultMaximumSegmentIndex"/>.</param>
        /// <param name="segmentSize">The number of items to include in each segment. See <see cref="DefaultNumberOfItemsInSegment"/>.</param>
        /// <param name="searchTimeoutInSeconds">The timeout for each search. See <see cref="DefaultSearchTimeoutInSeconds"/>. Zero indicates indefinite timeout.</param>
        /// <returns>Total count of objects across vault.</returns>
        /// <remarks>Note that <paramref name="searchTimeoutInSeconds"/> applies to the timeout on each segment search; if multiple segments are needed then the maximum time that this method takes to return will exceed the provided value.</remarks>
        internal static long ForEachSegment(
            this MFSearchBuilder builder,
            Func <Vault, SearchConditions, int> func,
            int startSegment           = 0,
            int segmentLimit           = MFSearchBuilderExtensionMethods.DefaultMaximumSegmentIndex,
            int segmentSize            = MFSearchBuilderExtensionMethods.DefaultNumberOfItemsInSegment,
            int searchTimeoutInSeconds = MFSearchBuilderExtensionMethods.DefaultSearchTimeoutInSeconds)
        {
            // Sanity.
            if (null == func)
            {
                throw new ArgumentNullException(nameof(func));
            }
            if (startSegment < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(startSegment), "The start segment must be greater than or equal to zero.");
            }
            if (segmentSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(segmentSize), "The segment size must be greater than zero.");
            }
            if (searchTimeoutInSeconds < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(searchTimeoutInSeconds), "The search timeout must be greater than zero, or zero to indicate an indefinite timeout");
            }

            // Set our start values.
            var  segment     = startSegment;
            long resultCount = 0;             // The total number of matched items in all segments.

            // Iterate over segments until we hit the sanity limit,
            // or until there are no items left to find.
            while (segment < segmentLimit)
            {
                // Make a copy of the builder that we can interact with and not
                // affect the one passed in.
                var internalBuilder = new MFSearchBuilder(builder.Vault, builder.Conditions);

                // Add a condition for the current segment that we want.
                internalBuilder.ObjectIdSegment(segment, segmentSize);

                // Execute the provided function.
                // This must return a count of items that were in the current segment,
                // but it may also execute other code against the items, depending on
                // what the calling function needs.
                var searchResultsCount = func(internalBuilder.Vault, internalBuilder.Conditions);

                // If we got no items back then we need to check whether a higher segment has items.
                if (searchResultsCount == 0)
                {
                    // Recreate the internal builder.
                    internalBuilder = new MFSearchBuilder(builder.Vault, builder.Conditions);

                    // Add a condition to see whether there are any items that have an ID in a higher segment.
                    internalBuilder.MinObjId(segment + 1, segmentSize);

                    // Find any matching items that exist in a higher segment.
                    var resultsTopId = internalBuilder
                                       .Vault
                                       .ObjectSearchOperations
                                       .SearchForObjectsByConditionsEx
                                       (
                        internalBuilder.Conditions,
                        MFSearchFlags.MFSearchFlagDisableRelevancyRanking,
                        SortResults: false,
                        MaxResultCount: 1,
                        SearchTimeoutInSeconds: searchTimeoutInSeconds
                                       );

                    // If there are none then break out of the while loop
                    // as there is no point checking further segments.
                    if (resultsTopId.Count == 0)
                    {
                        break;
                    }
                }

                // Increment the total count by the count in this segment.
                resultCount += searchResultsCount;

                // Advance to the next segment.
                segment += 1;
            }

            // Return the total number of matched items across all segments.
            return(resultCount);
        }
Example #5
0
        public string FindMultifile(Vault env)
        {
            var searchMultiFile = new MFSearchBuilder(env);

            searchMultiFile.Deleted(false);
            searchMultiFile.ObjType(MFBuiltInObjectType.MFBuiltInObjectTypeDocument);
            searchMultiFile.Conditions.AddPropertyCondition(22, MFConditionType.MFConditionTypeEqual, MFDataType.MFDatatypeBoolean, false);
            searchMultiFile.Class(this.Configuration.CurrentConfiguration.ProposalClass);

            var searchMFResults = searchMultiFile.FindEx();

            foreach (var searchResult in searchMFResults)
            {
                // If it is an MFD with one file then convert back.
                if (searchResult.Info.FilesCount == 1)
                {
                    // Set to SFD.
                    searchResult.SaveProperty(
                        (int)MFBuiltInPropertyDef.MFBuiltInPropertyDefSingleFileObject,
                        MFDataType.MFDatatypeBoolean,
                        true);

                    // Audit trail.


                    // Done.
                    return("");
                }

                try
                {
                    //Get multifile name
                    var MFTitle = searchResult.Title;


                    // Get a collection of documents for the document collection.
                    var createdItems = new Lookups();

                    // Get a copy of the current object's properties.
                    var propertiesCopy = this.GetNewObjectPropertyValues(searchResult.Properties);

                    // For each file, create a new object.
                    foreach (var file in searchResult.Info.Files.Cast <ObjectFile>())
                    {
                        // Add Component Type based on Title
                        if (file.Title.Contains("NPA"))
                        {
                            propertiesCopy.SetProperty(this.Configuration.CurrentConfiguration.ComponentTypeProperty, MFDataType.MFDatatypeLookup, 2);
                        }
                        else if (file.Title.Contains("EOI"))
                        {
                            propertiesCopy.SetProperty(this.Configuration.CurrentConfiguration.ComponentTypeProperty, MFDataType.MFDatatypeLookup, 3);
                        }
                        else if (file.Title.Contains("Price"))
                        {
                            propertiesCopy.SetProperty(this.Configuration.CurrentConfiguration.ComponentTypeProperty, MFDataType.MFDatatypeLookup, 4);
                        }
                        else if (file.Title.Contains("RFT"))
                        {
                            propertiesCopy.SetProperty(this.Configuration.CurrentConfiguration.ComponentTypeProperty, MFDataType.MFDatatypeLookup, 1);
                        }
                        else if (file.Title.Contains("RFP"))
                        {
                            propertiesCopy.SetProperty(this.Configuration.CurrentConfiguration.ComponentTypeProperty, MFDataType.MFDatatypeLookup, 1);
                        }

                        // Download the file.
                        var sourceObjectFiles = this.GetNewObjectSourceFiles(env, file);
                        propertiesCopy.SetProperty(0, MFDataType.MFDatatypeText, file.Title);
                        // Create the new object.
                        var createdObjectId = env.ObjectOperations
                                              .CreateNewObjectExQuick(
                            (int)MFBuiltInObjectType.MFBuiltInObjectTypeDocument,
                            propertiesCopy.Clone(),
                            sourceObjectFiles,
                            SFD: true);

                        createdItems.Add(-1, new Lookup
                        {
                            ObjectType = (int)MFBuiltInObjectType.MFBuiltInObjectTypeDocument,
                            Item       = createdObjectId,
                            // TODO: Version???
                        });
                    }

                    // Add the created documents to a property for the collection.
                    {
                        var collectionMembersPropertyValue = new PropertyValue
                        {
                            PropertyDef = (int)MFBuiltInPropertyDef.MFBuiltInPropertyDefCollectionMemberDocuments
                        };
                        collectionMembersPropertyValue.Value.SetValueToMultiSelectLookup(createdItems);
                        propertiesCopy.Add(-1, collectionMembersPropertyValue);
                    }

                    propertiesCopy.SetProperty(0, MFDataType.MFDatatypeText, MFTitle);
                    propertiesCopy.RemoveProperty(this.Configuration.CurrentConfiguration.ComponentTypeProperty);
                    propertiesCopy.SetProperty(100, MFDataType.MFDatatypeLookup, this.Configuration.CurrentConfiguration.ProposalCollectionClass);
                    // Create the document collection.
                    var documentCollectionObjVer = new ObjVer
                    {
                        Type = (int)MFBuiltInObjectType.MFBuiltInObjectTypeDocumentCollection,
                        ID   = env.ObjectOperations.CreateNewObjectExQuick(
                            (int)MFBuiltInObjectType.MFBuiltInObjectTypeDocumentCollection,
                            propertiesCopy)
                    };

                    // Can we reference the collection?
                    if (this.Configuration.CurrentConfiguration.DocumentCollectionReference.IsResolved)
                    {
                        // Find items which referenced this (old) document and instead reference the collection.
                        foreach (var objVerEx in env
                                 .ObjectOperations
                                 .GetRelationships(searchResult.ObjVer, MFRelationshipsMode.MFRelationshipsModeToThisObject)
                                 .Cast <ObjectVersion>()
                                 .Select(ov => new ObjVerEx(env, ov)))
                        {
                            var checkout = objVerEx.StartRequireCheckedOut();
                            objVerEx.AddLookup(
                                this.Configuration.CurrentConfiguration.DocumentCollectionReference.ID,
                                documentCollectionObjVer,
                                exactVersion: false);
                            objVerEx.SaveProperties();
                            objVerEx.EndRequireCheckedOut(checkout);
                        }
                    }

                    //Remove orignal File
                    {
                        searchResult.Delete();
                    }
                }
                catch (Exception e)
                {
                    SysUtils.ReportErrorToEventLog(e);

                    // Throw.
                    throw;
                }
            }
            return("");
        }