/// <summary> /// Adds a <see cref="SearchCondition"/> to the collection to check whether a property is not empty /// </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="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 PropertyNotEmpty ( this MFSearchBuilder searchBuilder, int propertyDef, 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."); } // What is the type of this property? var dataType = searchBuilder.Vault.PropertyDefOperations.GetPropertyDef(propertyDef).DataType; // Add the search condition. return(searchBuilder.AddPropertyValueSearchCondition ( propertyDef, dataType, null, MFConditionType.MFConditionTypeNotEqual, parentChildBehavior, indirectionLevels, null )); }
/// <inherit /> protected override void AddSearchCondition ( MFSearchBuilder mfSearchBuilder, int propertyDef, DateTime?value, MFConditionType conditionType = MFConditionType.MFConditionTypeEqual, MFParentChildBehavior parentChildBehavior = MFParentChildBehavior.MFParentChildBehaviorNone, DataFunctionCall dataFunctionCall = null, PropertyDefOrObjectTypes indirectionLevels = null ) { // Sanity. if (null == mfSearchBuilder) { throw new ArgumentNullException(nameof(mfSearchBuilder)); } // Call the property overload. mfSearchBuilder.Date ( propertyDef, // Value is not nullable in the real world, but needed here for the test to work. value ?? new DateTime(2020, 01, 01), conditionType, parentChildBehavior, indirectionLevels ); }
public static IEnumerable <object[]> GetValidValuesWithIndirectionLevels() { // Single indirection level by property. { var indirectionLevels = new PropertyDefOrObjectTypes(); indirectionLevels.AddPropertyDefIndirectionLevel(PropertyValueSearchConditionTestBase.TestLookupPropertyId); yield return(new object[] { PropertyValueSearchConditionTestBase.TestDatePropertyId, DateTime.Now.Date, MFConditionType.MFConditionTypeEqual, MFParentChildBehavior.MFParentChildBehaviorNone, indirectionLevels }); } // Single indirection level by object type. { var indirectionLevels = new PropertyDefOrObjectTypes(); indirectionLevels.AddObjectTypeIndirectionLevel(PropertyValueSearchConditionTestBase.TestProjectObjectTypeId); yield return(new object[] { PropertyValueSearchConditionTestBase.TestDatePropertyId, DateTime.Now.Date, MFConditionType.MFConditionTypeEqual, MFParentChildBehavior.MFParentChildBehaviorNone, indirectionLevels }); } // Multiple indirection levels by property. { var indirectionLevels = new PropertyDefOrObjectTypes(); indirectionLevels.AddPropertyDefIndirectionLevel(PropertyValueSearchConditionTestBase.TestLookupPropertyId); indirectionLevels.AddPropertyDefIndirectionLevel(PropertyValueSearchConditionTestBase.TestMultiSelectLookupPropertyId); yield return(new object[] { PropertyValueSearchConditionTestBase.TestDatePropertyId, DateTime.Now.Date, MFConditionType.MFConditionTypeEqual, MFParentChildBehavior.MFParentChildBehaviorNone, indirectionLevels }); } // Multiple indirection levels by object type. { var indirectionLevels = new PropertyDefOrObjectTypes(); indirectionLevels.AddObjectTypeIndirectionLevel(PropertyValueSearchConditionTestBase.TestProjectObjectTypeId); indirectionLevels.AddObjectTypeIndirectionLevel(PropertyValueSearchConditionTestBase.TestCustomerObjectTypeId); yield return(new object[] { PropertyValueSearchConditionTestBase.TestDatePropertyId, DateTime.Now.Date, MFConditionType.MFConditionTypeEqual, MFParentChildBehavior.MFParentChildBehaviorNone, indirectionLevels }); } }
/// <summary> /// Adds an indirection level to the collection that represents /// a relationship using any/all properties of a given type. /// </summary> /// <param name="indirectionLevels">The collection to add to.</param> /// <param name="objectTypeId">The Id of the object type.</param> /// <returns>The <paramref name="indirectionLevels"/>, for chaining.</returns> public static PropertyDefOrObjectTypes AddObjectTypeIndirectionLevel ( this PropertyDefOrObjectTypes indirectionLevels, int objectTypeId ) { // Sanity. if (null == indirectionLevels) { throw new ArgumentNullException(nameof(indirectionLevels)); } // Ensure that the object type id is >= 0. if (objectTypeId < 0) { throw new ArgumentOutOfRangeException(nameof(objectTypeId)); } // Add the object type indirection level. indirectionLevels.Add(-1, new PropertyDefOrObjectType() { ID = objectTypeId, PropertyDef = false }); // Return the indirection levels for chaining. return(indirectionLevels); }
/// <inherit /> protected override void AddSearchCondition ( MFSearchBuilder mfSearchBuilder, int propertyDef, string value, MFConditionType conditionType = MFConditionType.MFConditionTypeEqual, MFParentChildBehavior parentChildBehavior = MFParentChildBehavior.MFParentChildBehaviorNone, DataFunctionCall dataFunctionCall = null, PropertyDefOrObjectTypes indirectionLevels = null ) { // Sanity. if (null == mfSearchBuilder) { throw new ArgumentNullException(nameof(mfSearchBuilder)); } // Call the property overload. mfSearchBuilder.YearAndMonth ( propertyDef, 2020, 1, conditionType, parentChildBehavior, indirectionLevels ); }
/// <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 month component in the property value , equivalent to using /// a <see cref="DataFunctionCall" /> set to <see cref="DataFunctionCall.SetDataMonth" />. /// </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="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="indirectionLevels">The indirection levels (from the search object) to access the property to match.</param> /// <param name="parentChildBehavior">Whether to accept matches to parent/child values as well (defaults to <see cref="MFParentChildBehavior.MFParentChildBehaviorNone"/>).</param> /// <returns>The <paramref name="searchBuilder"/> provided, for chaining.</returns> public static MFSearchBuilder Month ( this MFSearchBuilder searchBuilder, int propertyDef, 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."); } // 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.SetDataMonth(); break; default: throw new ArgumentException($"Property {propertyDef} is not a date or timestamp property.", nameof(propertyDef)); } // Use the property method. return(searchBuilder.Property ( propertyDef, month.ToString("00"), conditionType, parentChildBehavior, indirectionLevels, dataFunctionCall )); }
/// <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 component in the property value , equivalent to using /// a <see cref="DataFunctionCall" /> set to <see cref="DataFunctionCall.SetDataYear"/>. /// </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="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 Year ( this MFSearchBuilder searchBuilder, int propertyDef, int year, 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 (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 integer using a data function call. dataFunctionCall = new DataFunctionCall(); dataFunctionCall.SetDataYear(); 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, conditionType, parentChildBehavior, indirectionLevels, dataFunctionCall )); }
/// <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, long?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; // If it is not valid 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> /// Adds a <see cref="SearchCondition"/> to the collection to represent a "one of" search condition (https://developer.m-files.com/APIs/COM-API/Searching/SearchConditions/#executing-a-one-of-search). /// </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="lookups">The items to search for (the object must have the property set to one of these).</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 PropertyOneOf ( this MFSearchBuilder searchBuilder, int propertyDef, IEnumerable <Lookup> lookups, MFParentChildBehavior parentChildBehavior = MFParentChildBehavior.MFParentChildBehaviorNone, PropertyDefOrObjectTypes indirectionLevels = null ) { // Use the other overload. return(searchBuilder?.PropertyOneOf ( propertyDef, lookups?.Select(lookup => lookup.Item), parentChildBehavior, indirectionLevels )); }
/// <summary> /// Adds a <see cref="SearchCondition"/> to the collection to represent a "one of" search condition (https://developer.m-files.com/APIs/COM-API/Searching/SearchConditions/#executing-a-one-of-search). /// </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="objects">The items to search for (the object must have the property set to one of these).</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 PropertyOneOf ( this MFSearchBuilder searchBuilder, int propertyDef, IEnumerable <ObjVerEx> objects, MFParentChildBehavior parentChildBehavior = MFParentChildBehavior.MFParentChildBehaviorNone, PropertyDefOrObjectTypes indirectionLevels = null ) { // Use the other overload. return(searchBuilder.PropertyOneOf ( propertyDef, objects?.Where(o => o != null)?.Select(objVerEx => objVerEx.ID), parentChildBehavior, indirectionLevels )); }
public void SearchConditionIsCorrect_WithIndirectionLevels ( int propertyDef, long?input, MFConditionType conditionType, MFParentChildBehavior parentChildBehavior, PropertyDefOrObjectTypes indirectionLevels ) { base.AssertSearchConditionIsCorrect ( propertyDef, MFDataType.MFDatatypeInteger64, input, conditionType, parentChildBehavior, indirectionLevels ); }
/// <summary> /// Adds a <see cref="SearchCondition"/> to the collection to represent a "one of" search condition (https://developer.m-files.com/APIs/COM-API/Searching/SearchConditions/#executing-a-one-of-search). /// </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="identifiers">The items to search for (the object must have the property set to one of these).</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 PropertyOneOf ( this MFSearchBuilder searchBuilder, int propertyDef, IEnumerable <MFIdentifier> identifiers, MFParentChildBehavior parentChildBehavior = MFParentChildBehavior.MFParentChildBehaviorNone, PropertyDefOrObjectTypes indirectionLevels = null ) { // Use the other overload. return(searchBuilder?.PropertyOneOf ( propertyDef, identifiers? .Where(i => i != null) .Select(identifier => { // Ensure that we're resolved. try { // If we have to resolve it and have no vault reference then die. if (false == identifier.IsResolved) { if (null == searchBuilder?.Vault) { throw new InvalidOperationException($"The search builder or vault reference is null, so the identifier with alias/GUID {identifier.Alias} cannot be resolved."); } } // Resolve if needed. return identifier .Resolve(searchBuilder?.Vault, typeof(PropertyDef)) .ID; } catch (Exception e) { throw new Exception($"Could not resolve the identifier with alias/GUID {identifier.Alias} in the current vault", e); } }), parentChildBehavior, indirectionLevels )); }
/// <summary> /// Adds a <see cref="SearchCondition"/> to the collection to represent a "one of" search condition (https://developer.m-files.com/APIs/COM-API/Searching/SearchConditions/#executing-a-one-of-search). /// </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="lookupIds">The ids to search for (the object must have the property set to one of these IDs).</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 PropertyOneOf ( this MFSearchBuilder searchBuilder, int propertyDef, IEnumerable <int> lookupIds, 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 (null == lookupIds || false == lookupIds.Any()) { throw new ArgumentException("The lookup collection does not contain any items.", nameof(lookupIds)); } // What is the type of this property? var dataType = searchBuilder.Vault.PropertyDefOperations.GetPropertyDef(propertyDef).DataType; // If it is not valid then throw. if (dataType != MFDataType.MFDatatypeLookup && dataType != MFDataType.MFDatatypeMultiSelectLookup) { throw new ArgumentException($"Property {propertyDef} is not a lookup or multi-select lookup property.", nameof(propertyDef)); } // Add the search condition. return(searchBuilder.AddPropertyValueSearchCondition ( propertyDef, MFDataType.MFDatatypeMultiSelectLookup, lookupIds.ToArray(), MFConditionType.MFConditionTypeEqual, parentChildBehavior, indirectionLevels )); }
public void SearchConditionIsCorrect ( int propertyDef, DateTime?input, MFConditionType conditionType, MFParentChildBehavior parentChildBehavior, PropertyDefOrObjectTypes indirectionLevels ) { base.AssertSearchConditionIsCorrect ( propertyDef, MFDataType.MFDatatypeDate, input, conditionType, parentChildBehavior, indirectionLevels ); }
/// <inherit /> protected override void AddSearchCondition ( MFSearchBuilder mfSearchBuilder, int propertyDef, int[] value, MFConditionType conditionType = MFConditionType.MFConditionTypeEqual, MFParentChildBehavior parentChildBehavior = MFParentChildBehavior.MFParentChildBehaviorNone, DataFunctionCall dataFunctionCall = null, PropertyDefOrObjectTypes indirectionLevels = null ) { // Sanity. if (null == mfSearchBuilder) { throw new ArgumentNullException(nameof(mfSearchBuilder)); } // Use our extension method. mfSearchBuilder.PropertyOneOf(propertyDef, value, parentChildBehavior, indirectionLevels); }
public void SearchConditionIsCorrect_TimeStrippedFromDateProperties ( ) { // Create the search builder. var searchBuilder = new MFSearchBuilder(this.GetVaultMock().Object); // Set up the expected data. var propertyDef = PropertyValueSearchConditionTestBase.TestDatePropertyId; var parentChildBehavior = MFParentChildBehavior.MFParentChildBehaviorNone; var conditionType = MFConditionType.MFConditionTypeEqual; var indirectionLevels = new PropertyDefOrObjectTypes(); var val = DateTime.Now; // If we happen to run right at midnight then make sure we have a time component. if (val.Hour == 0 && val.Minute == 0) { val = val.AddMinutes(30); } // Add the condition. searchBuilder.Property ( propertyDef, val, conditionType, parentChildBehavior, indirectionLevels: indirectionLevels ); base.AssertSearchConditionIsCorrect ( propertyDef, MFDataType.MFDatatypeDate, val.Date, // Ensure that the time was stripped! conditionType, parentChildBehavior, indirectionLevels ); }
/// <summary> /// Adds a <see cref="SearchCondition"/> to the collection for a <see cref="MFDataType.MFDatatypeText"/> /// or <see cref="MFDataType.MFDatatypeMultiLineText"/> 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, string 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.MFDataFunctionMonth: { // If it's a timestamp or date then convert to text. if (dataType == MFDataType.MFDatatypeTimestamp || dataType == MFDataType.MFDatatypeDate) { dataType = MFDataType.MFDatatypeText; } // Validate the value. if (value?.Length != 2) { throw new ArgumentException ( $"The value {value} should contain a two-digit month number (e.g. '03').", nameof(value) ); } // Is it an integer? if (false == Int32.TryParse(value, out int month)) { throw new ArgumentException ( $"The value {value} should contain a two-digit month number (e.g. '03').", nameof(value) ); } // Validate the month. if (month <= 0 || month > 12) { throw new ArgumentException ( $"The month value {month} should be between 1 and 12.", nameof(value) ); } } break; case MFDataFunction.MFDataFunctionYearAndMonth: { // If it's a timestamp or date then convert to text. if (dataType == MFDataType.MFDatatypeTimestamp || dataType == MFDataType.MFDatatypeDate) { dataType = MFDataType.MFDatatypeText; } // Also, validate the value. var splitValue = (value ?? "").Split("-".ToCharArray()); if (splitValue.Length != 2 || splitValue[0].Length != 4 || splitValue[1].Length != 2) { throw new ArgumentException ( $"The value {value} is not of the expected format (YYYY-MM).", nameof(value) ); } // Is it a valid set of integers? { if (false == Int32.TryParse(splitValue[0], out _) || false == Int32.TryParse(splitValue[1], out int month)) { throw new ArgumentException ( $"The value {value} is not of the expected format (YYYY-MM).", nameof(value) ); } // Validate the month. if (month <= 0 || month > 12) { throw new ArgumentException ( $"The month value {month} should be between 1 and 12.", nameof(value) ); } } } break; } } // If it is not okay then throw. if (dataType != MFDataType.MFDatatypeText && dataType != MFDataType.MFDatatypeMultiLineText) { throw new ArgumentException($"Property {propertyDef} is not a text property.", nameof(propertyDef)); } // Add the search condition. return(searchBuilder.AddPropertyValueSearchCondition ( propertyDef, dataType, value, conditionType, parentChildBehavior, indirectionLevels, dataFunctionCall )); }
/// <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> /// Adds a <see cref="SearchCondition"/> to the collection for a <see cref="MFDataType.MFDatatypeDate"/> /// or <see cref="MFDataType.MFDatatypeTimestamp"/> 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, DateTime?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.MFDataFunctionDate: // If it's a timestamp then convert to date. if (dataType == MFDataType.MFDatatypeTimestamp) { dataType = MFDataType.MFDatatypeDate; } break; } } // If it is not valid then throw. if (dataType != MFDataType.MFDatatypeDate && dataType != MFDataType.MFDatatypeTimestamp) { throw new ArgumentException($"Property {propertyDef} is not a date or timestamp property.", nameof(propertyDef)); } //// If it's a date and the value has a time component then strip it. if (dataType == MFDataType.MFDatatypeDate) { value = value?.Date; } // Add the search condition. return(searchBuilder.AddPropertyValueSearchCondition ( propertyDef, dataType, value, conditionType, parentChildBehavior, indirectionLevels, dataFunctionCall )); }