public IEnumerable<Field> Index(object val, PropertyDescriptorCollection properties, IndexDefinition indexDefinition)
 {
     return (from property in properties.Cast<PropertyDescriptor>()
             let name = property.Name
             where name != "__document_id"
             let value = property.GetValue(val)
             where value != null
             select new Field(name, ToIndexableString(value, indexDefinition.GetIndex(name)), indexDefinition.GetStorage(name), indexDefinition.GetIndex(name)));
 }
        private static AbstractField Createfield(string name, object value, IndexDefinition indexDefinition, Field.Store defaultStorage)
        {
            if (indexDefinition.GetIndex(name, Field.Index.ANALYZED) == Field.Index.NOT_ANALYZED || value is string)
                return new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.ANALYZED));

            if (value is int)
            {
                return new Field(name, JsonLuceneNumberConverter.NumberToString((int)value), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));

            }
            if (value is long)
            {
                return new Field(name, JsonLuceneNumberConverter.NumberToString((long)value), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));

            }
            if(value is decimal)
            {
                return new Field(name, JsonLuceneNumberConverter.NumberToString((decimal)value), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
            }
            if (value is float)
            {
                return new Field(name, JsonLuceneNumberConverter.NumberToString((float)value), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
            }
            if (value is double)
            {
                return new Field(name, JsonLuceneNumberConverter.NumberToString((double)value), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
            }
            if (value is DateTime)
            {
                return new Field(name, DateTools.DateToString((DateTime)value, DateTools.Resolution.MILLISECOND),
                    indexDefinition.GetStorage(name, defaultStorage),
                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
            }
            return new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                             indexDefinition.GetIndex(name, Field.Index.ANALYZED));
        }
		/// <summary>
		/// This method generate the fields for indexing documents in lucene from the values.
		/// Given a name and a value, it has the following behavior:
		/// * If the value is enumerable, index all the items in the enumerable under the same field name
		/// * If the value is null, create a single field with the supplied name with the unanalyzed value 'NULL_VALUE'
		/// * If the value is string or was set to not analyzed, create a single field with the supplied name
		/// * If the value is date, create a single field with millisecond precision with the supplied name
		/// * If the value is numeric (int, long, double, decimal, or float) will create two fields:
		///		1. with the supplied name, containing the numeric value as an unanalyzed string - useful for direct queries
		///		2. with the name: name +'_Range', containing the numeric value in a form that allows range queries
		/// </summary>
		private static IEnumerable<AbstractField> CreateFields(string name, object value, IndexDefinition indexDefinition, Field.Store defaultStorage)
		{
            if(string.IsNullOrWhiteSpace(name))
                throw new ArgumentException("Field must be not null, not empty and cannot contain whitespace", "name");

            if (char.IsLetter(name[0]) == false &&
                name[0] != '_')
            {
                name = "_" + name;
            }

			if (value == null)
			{
				yield return new Field(name, Constants.NullValue, indexDefinition.GetStorage(name, defaultStorage),
								 Field.Index.NOT_ANALYZED);
				yield break;
			}
			if (value is DynamicNullObject)
			{
				if(((DynamicNullObject)value ).IsExplicitNull)
				{
					yield return new Field(name, Constants.NullValue, indexDefinition.GetStorage(name, defaultStorage),
							 Field.Index.NOT_ANALYZED);
				}
				yield break;
			}

            if(value is AbstractField)
            {
                yield return (AbstractField)value;
                yield break;
            }


			var itemsToIndex = value as IEnumerable;
			if( itemsToIndex != null && ShouldTreatAsEnumerable(itemsToIndex))
			{
                yield return new Field(name + "_IsArray", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS);
                foreach (var itemToIndex in itemsToIndex)
				{
                    foreach (var field in CreateFields(name, itemToIndex, indexDefinition, defaultStorage))
                    {
                        yield return field;
                    }
				}
				yield break;
			}

            if (indexDefinition.GetIndex(name, null) == Field.Index.NOT_ANALYZED)// explicitly not analyzed
            {
                yield return new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
                yield break;
			    
            }
			if (value is string) 
			{
			    var index = indexDefinition.GetIndex(name, Field.Index.ANALYZED);
			    yield return new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                 index); 
				yield break;
			}

			if (value is DateTime)
			{
				yield return new Field(name, DateTools.DateToString((DateTime)value, DateTools.Resolution.MILLISECOND),
					indexDefinition.GetStorage(name, defaultStorage),
					indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
			}
            else if(value is bool)
            {
                yield return new Field(name, ((bool) value) ? "true" : "false", indexDefinition.GetStorage(name, defaultStorage),
                              indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));

            }
			else if(value is IConvertible) // we need this to store numbers in invariant format, so JSON could read them
			{
				var convert = ((IConvertible) value);
				yield return new Field(name, convert.ToString(CultureInfo.InvariantCulture), indexDefinition.GetStorage(name, defaultStorage),
				                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
			}
			else if (value is DynamicJsonObject)
			{
				var inner = ((DynamicJsonObject)value).Inner;
				yield return new Field(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS);
				yield return new Field(name, inner.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
			}
			else 
			{
				yield return new Field(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS);
				yield return new Field(name, JToken.FromObject(value).ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
			}


			var numericField = new NumericField(name + "_Range", indexDefinition.GetStorage(name, defaultStorage), true);
			if (value is int)
			{
				if(indexDefinition.GetSortOption(name) == SortOptions.Long)
					yield return numericField.SetLongValue((int)value);
				else
					yield return numericField.SetIntValue((int)value);
			}
			if (value is long)
			{
				yield return numericField
					.SetLongValue((long) value);

			}
			if (value is decimal)
            {
				yield return numericField
					.SetDoubleValue((double)(decimal)value);
            }
			if (value is float)
            {
				if (indexDefinition.GetSortOption(name) == SortOptions.Double)
					yield return numericField.SetDoubleValue((float)value);
				else
            		yield return numericField.SetFloatValue((float) value);
            }
			if (value is double)
            {
				yield return numericField
					.SetDoubleValue((double)value);
            }
		}
		/// <summary>
		/// This method generate the fields for indexing documents in lucene from the values.
		/// Given a name and a value, it has the following behavior:
		/// * If the value is enumerable, index all the items in the enumerable under the same field name
		/// * If the value is null, create a single field with the supplied name with the unanalyzed value 'NULL_VALUE'
		/// * If the value is string or was set to not analyzed, create a single field with the supplied name
		/// * If the value is date, create a single field with millisecond precision with the supplied name
		/// * If the value is numeric (int, long, double, decimal, or float) will create two fields:
		///		1. with the supplied name, containing the numeric value as an unanalyzed string - useful for direct queries
		///		2. with the name: name +'_Range', containing the numeric value in a form that allows range queries
		/// </summary>
		private IEnumerable<AbstractField> CreateFields(string name, object value, IndexDefinition indexDefinition, Field.Store defaultStorage)
		{
			if(string.IsNullOrWhiteSpace(name))
				throw new ArgumentException("Field must be not null, not empty and cannot contain whitespace", "name");

			if (char.IsLetter(name[0]) == false &&
				name[0] != '_')
			{
				name = "_" + name;
			}

			if (value == null)
			{
				yield return CreateFieldWithCaching(name, Constants.NullValue, indexDefinition.GetStorage(name, defaultStorage),
								 Field.Index.NOT_ANALYZED_NO_NORMS);
				yield break;
			}
			if(Equals(value, string.Empty))
			{
				yield return CreateFieldWithCaching(name, Constants.EmptyString, indexDefinition.GetStorage(name, defaultStorage),
							 Field.Index.NOT_ANALYZED_NO_NORMS);
				yield break;
			}
			if (value is DynamicNullObject)
			{
				if(((DynamicNullObject)value ).IsExplicitNull)
				{
					yield return CreateFieldWithCaching(name, Constants.NullValue, indexDefinition.GetStorage(name, defaultStorage),
							 Field.Index.NOT_ANALYZED_NO_NORMS);
				}
				yield break;
			}

			if(value is AbstractField)
			{
				yield return (AbstractField)value;
				yield break;
			}
			if(value is byte[])
			{
				yield return CreateBinaryFieldWithCaching(name, (byte[])value, indexDefinition.GetStorage(name, defaultStorage));
				yield break;
			}

			var itemsToIndex = value as IEnumerable;
			if( itemsToIndex != null && ShouldTreatAsEnumerable(itemsToIndex))
			{
				yield return new Field(name + "_IsArray", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS);
				int count = 1;
				foreach (var itemToIndex in itemsToIndex)
				{
					multipleItemsSameFieldCount.Add(count++);
					foreach (var field in CreateFields(name, itemToIndex, indexDefinition, defaultStorage))
					{
						yield return field;
					}
					multipleItemsSameFieldCount.RemoveAt(multipleItemsSameFieldCount.Count - 1);
				}
				yield break;
			}

			var fieldIndexingOptions = indexDefinition.GetIndex(name, null);
			if (fieldIndexingOptions == Field.Index.NOT_ANALYZED || fieldIndexingOptions == Field.Index.NOT_ANALYZED_NO_NORMS)// explicitly not analyzed
			{
				if (value is DateTime)
				{
				    var val = (DateTime) value;
					var postFix = val.Kind == DateTimeKind.Utc ? "Z" : "";
					yield return CreateFieldWithCaching(name, val.ToString(Default.DateTimeFormatsToWrite) + postFix, indexDefinition.GetStorage(name, defaultStorage),
									   indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS));
				}
				else if(value is DateTimeOffset)
				{
					var val = (DateTimeOffset)value;
					yield return CreateFieldWithCaching(name, val.ToString(Default.DateTimeOffsetFormatsToWrite), indexDefinition.GetStorage(name, defaultStorage),
									   indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS));
				}
				else
				{
					yield return CreateFieldWithCaching(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
										   indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS));
				}
				yield break;
			    
			}
			if (value is string) 
			{
			    var index = indexDefinition.GetIndex(name, Field.Index.ANALYZED);
				yield return CreateFieldWithCaching(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
								 index); 
				yield break;
			}

			if (value is DateTime)
			{
				yield return CreateFieldWithCaching(name, DateTools.DateToString((DateTime)value, DateTools.Resolution.MILLISECOND),
					indexDefinition.GetStorage(name, defaultStorage),
					indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS));
			}
			else if (value is DateTimeOffset)
			{
				yield return CreateFieldWithCaching(name, DateTools.DateToString(((DateTimeOffset)value).UtcDateTime, DateTools.Resolution.MILLISECOND),
					indexDefinition.GetStorage(name, defaultStorage),
					indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS));
			}
			else if(value is bool)
			{
				yield return new Field(name, ((bool) value) ? "true" : "false", indexDefinition.GetStorage(name, defaultStorage),
							  indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS));

			}
			else if(value is IConvertible) // we need this to store numbers in invariant format, so JSON could read them
			{
				var convert = ((IConvertible) value);
				yield return CreateFieldWithCaching(name, convert.ToString(CultureInfo.InvariantCulture), indexDefinition.GetStorage(name, defaultStorage),
									   indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS));
			}
			else if (value is IDynamicJsonObject)
			{
				var inner = ((IDynamicJsonObject)value).Inner;
				yield return CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS);
				yield return CreateFieldWithCaching(name, inner.ToString(), indexDefinition.GetStorage(name, defaultStorage),
									   indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS));
			}
			else 
			{
				yield return CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS);
				yield return CreateFieldWithCaching(name, RavenJToken.FromObject(value).ToString(), indexDefinition.GetStorage(name, defaultStorage),
									   indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS));
			}


			foreach (var numericField in CreateNumericFieldWithCaching(name, value, defaultStorage)) 
				yield return numericField;
		}
		/// <summary>
		/// This method generate the fields for indexing documents in lucene from the values.
		/// Given a name and a value, it has the following behavior:
		/// * If the value is null, create a single field with the supplied name with the unanalyzed value 'NULL_VALUE'
		/// * If the value is string or was set to not analyzed, create a single field with the supplied name
		/// * If the value is date, create a single field with millisecond precision with the supplied name
		/// * If the value is numeric (int, long, double, decimal, or float) will create two fields:
		///		1. with the supplied name, containing the numeric value as an unanalyzed string - useful for direct queries
		///		2. with the name: name +'_Range', containing the numeric value in a form that allows range queries
		/// </summary>
		private static IEnumerable<AbstractField> CreateFields(string name, object value, IndexDefinition indexDefinition, Field.Store defaultStorage)
		{
			if (value == null)
			{
				yield return new Field(name, "NULL_VALUE", indexDefinition.GetStorage(name, defaultStorage),
								 Field.Index.NOT_ANALYZED);
				yield break;
			}

			var fields = value as IEnumerable<AbstractField>;
			if(fields != null)
			{
				foreach (var field in fields)
				{
					yield return field;
				}
				yield break;
			}

            if (indexDefinition.GetIndex(name, null) == Field.Index.NOT_ANALYZED)// explicitly not analyzed
            {
                yield return new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
                yield break;
			    
            }
			if (value is string) 
			{
			    var index = indexDefinition.GetIndex(name, Field.Index.ANALYZED);
			    yield return new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                 index); 
				yield break;
			}

			if (value is DateTime)
			{
				yield return new Field(name, DateTools.DateToString((DateTime)value, DateTools.Resolution.MILLISECOND),
					indexDefinition.GetStorage(name, defaultStorage),
					indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
			}
            else if(value is bool)
            {
                yield return new Field(name, ((bool) value) ? "true" : "false", indexDefinition.GetStorage(name, defaultStorage),
                              indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));

            }
			else if(value is IConvertible) // we need this to store numbers in invariant format, so JSON could read them
			{
				var convert = ((IConvertible) value);
				yield return new Field(name, convert.ToString(CultureInfo.InvariantCulture), indexDefinition.GetStorage(name, defaultStorage),
				                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
			}
			else if (value is DynamicJsonObject)
			{
				var inner = ((DynamicJsonObject)value).Inner;
				yield return new Field(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS);
				yield return new Field(name, inner.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
			}
			else 
			{
				yield return new Field(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS);
				yield return new Field(name, JToken.FromObject(value).ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
			}


			var numericField = new NumericField(name + "_Range", indexDefinition.GetStorage(name, defaultStorage), true);
			if (value is int)
			{
				if(indexDefinition.GetSortOption(name) == SortOptions.Long)
					yield return numericField.SetLongValue((int)value);
				else
					yield return numericField.SetIntValue((int)value);
			}
			if (value is long)
			{
				yield return numericField
					.SetLongValue((long) value);

			}
			if (value is decimal)
            {
				yield return numericField
					.SetDoubleValue((double)(decimal)value);
            }
			if (value is float)
            {
				if (indexDefinition.GetSortOption(name) == SortOptions.Double)
					yield return numericField.SetDoubleValue((float)value);
				else
            		yield return numericField.SetFloatValue((float) value);
            }
			if (value is double)
            {
				yield return numericField
					.SetDoubleValue((double)value);
            }
		}
        /// <summary>
        /// This method generate the fields for indexing documents in lucene from the values.
        /// Given a name and a value, it has the following behavior:
        /// * If the value is enumerable, index all the items in the enumerable under the same field name
        /// * If the value is null, create a single field with the supplied name with the unanalyzed value 'NULL_VALUE'
        /// * If the value is string or was set to not analyzed, create a single field with the supplied name
        /// * If the value is date, create a single field with millisecond precision with the supplied name
        /// * If the value is numeric (int, long, double, decimal, or float) will create two fields:
        ///		1. with the supplied name, containing the numeric value as an unanalyzed string - useful for direct queries
        ///		2. with the name: name +'_Range', containing the numeric value in a form that allows range queries
        /// </summary>
        public IEnumerable <AbstractField> CreateFields(string name, object value, Field.Store defaultStorage, bool nestedArray = false)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentException("Field must be not null, not empty and cannot contain whitespace", "name");
            }

            if (char.IsLetter(name[0]) == false &&
                name[0] != '_')
            {
                name = "_" + name;
            }

            var fieldIndexingOptions = indexDefinition.GetIndex(name, null);
            var storage = indexDefinition.GetStorage(name, defaultStorage);

            if (value == null)
            {
                yield return(CreateFieldWithCaching(name, Constants.NullValue, storage,
                                                    Field.Index.NOT_ANALYZED_NO_NORMS));

                yield break;
            }
            if (Equals(value, string.Empty))
            {
                yield return(CreateFieldWithCaching(name, Constants.EmptyString, storage,
                                                    Field.Index.NOT_ANALYZED_NO_NORMS));

                yield break;
            }
            if (value is DynamicNullObject)
            {
                if (((DynamicNullObject)value).IsExplicitNull)
                {
                    var sortOptions = indexDefinition.GetSortOption(name);
                    if (sortOptions != null && sortOptions.Value != SortOptions.None)
                    {
                        yield break;                         // we don't emit null for sorting
                    }
                    yield return(CreateFieldWithCaching(name, Constants.NullValue, storage,
                                                        Field.Index.NOT_ANALYZED_NO_NORMS));
                }
                yield break;
            }
            var boostedValue = value as BoostedValue;

            if (boostedValue != null)
            {
                foreach (var field in CreateFields(name, boostedValue.Value, storage))
                {
                    field.Boost     = boostedValue.Boost;
                    field.OmitNorms = false;
                    yield return(field);
                }
                yield break;
            }


            var abstractField = value as AbstractField;

            if (abstractField != null)
            {
                yield return(abstractField);

                yield break;
            }
            var bytes = value as byte[];

            if (bytes != null)
            {
                yield return(CreateBinaryFieldWithCaching(name, bytes, storage, fieldIndexingOptions));

                yield break;
            }

            var itemsToIndex = value as IEnumerable;

            if (itemsToIndex != null && ShouldTreatAsEnumerable(itemsToIndex))
            {
                var sentArrayField = false;
                int count          = 1;
                foreach (var itemToIndex in itemsToIndex)
                {
                    if (nestedArray == false && !Equals(storage, Field.Store.NO) && sentArrayField == false)
                    {
                        sentArrayField = true;
                        yield return(new Field(name + "_IsArray", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
                    }

                    if (CanCreateFieldsForNestedArray(itemToIndex, fieldIndexingOptions))
                    {
                        multipleItemsSameFieldCount.Add(count++);
                        foreach (var field in CreateFields(name, itemToIndex, storage, nestedArray: true))
                        {
                            yield return(field);
                        }
                        multipleItemsSameFieldCount.RemoveAt(multipleItemsSameFieldCount.Count - 1);
                    }
                }
                yield break;
            }

            if (Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED) ||
                Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED_NO_NORMS))                // explicitly not analyzed
            {
                // date time and date time offset have the same structure fo analyzed and not analyzed.
                if (!(value is DateTime) && !(value is DateTimeOffset))
                {
                    yield return(CreateFieldWithCaching(name, value.ToString(), storage,
                                                        indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));

                    yield break;
                }
            }
            if (value is string)
            {
                var index = indexDefinition.GetIndex(name, Field.Index.ANALYZED);
                yield return(CreateFieldWithCaching(name, value.ToString(), storage,
                                                    index));

                yield break;
            }

            if (value is DateTime)
            {
                var val = (DateTime)value;
                yield return(CreateFieldWithCaching(name, val.ToString(Default.DateTimeFormatsToWrite), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else if (value is DateTimeOffset)
            {
                var val = (DateTimeOffset)value;
                yield return(CreateFieldWithCaching(name, val.UtcDateTime.ToString(Default.DateTimeFormatsToWrite), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else if (value is bool)
            {
                yield return(new Field(name, ((bool)value) ? "true" : "false", storage,
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else if (value is decimal)
            {
                var d = (decimal)value;
                var s = d.ToString(CultureInfo.InvariantCulture);
                if (s.Contains('.'))
                {
                    s = s.TrimEnd('0');
                    if (s.EndsWith("."))
                    {
                        s = s.Substring(0, s.Length - 1);
                    }
                }
                yield return(CreateFieldWithCaching(name, s, storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else if (value is IConvertible)             // we need this to store numbers in invariant format, so JSON could read them
            {
                var convert = ((IConvertible)value);
                yield return(CreateFieldWithCaching(name, convert.ToString(CultureInfo.InvariantCulture), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else if (value is IDynamicJsonObject)
            {
                var inner = ((IDynamicJsonObject)value).Inner;
                yield return(CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

                yield return(CreateFieldWithCaching(name, inner.ToString(Formatting.None), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else
            {
                yield return(CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

                yield return(CreateFieldWithCaching(name, RavenJToken.FromObject(value).ToString(Formatting.None), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }


            foreach (var numericField in CreateNumericFieldWithCaching(name, value, storage))
            {
                yield return(numericField);
            }
        }
        private IEnumerable <AbstractField> CreateRegularFields(string name, object value, Field.Store defaultStorage, bool nestedArray = false, Field.TermVector defaultTermVector = Field.TermVector.NO, Field.Index?analyzed = null)
        {
            var fieldIndexingOptions = analyzed ?? indexDefinition.GetIndex(name, null);
            var storage    = indexDefinition.GetStorage(name, defaultStorage);
            var termVector = indexDefinition.GetTermVector(name, defaultTermVector);

            if (fieldIndexingOptions == Field.Index.NO && storage == Field.Store.NO && termVector == Field.TermVector.NO)
            {
                yield break;
            }

            if (fieldIndexingOptions == Field.Index.NO && storage == Field.Store.NO)
            {
                fieldIndexingOptions = Field.Index.ANALYZED;                 // we have some sort of term vector, forcing index to be analyzed, then.
            }

            if (value == null)
            {
                yield return(CreateFieldWithCaching(name, Constants.NullValue, storage,
                                                    Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));

                yield break;
            }

            CheckIfSortOptionsAndInputTypeMatch(name, value);

            var attachmentFoIndexing = value as AttachmentForIndexing;

            if (attachmentFoIndexing != null)
            {
                if (database == null)
                {
                    throw new InvalidOperationException(
                              "Cannot use attachment for indexing if the database parameter is null. This is probably a RavenDB bug");
                }

                var attachment = database.Attachments.GetStatic(attachmentFoIndexing.Key);
                if (attachment == null)
                {
                    yield break;
                }

                var fieldWithCaching = CreateFieldWithCaching(name, string.Empty, Field.Store.NO, fieldIndexingOptions, termVector);

                if (database.TransactionalStorage.IsAlreadyInBatch)
                {
                    var streamReader = new StreamReader(attachment.Data());
                    fieldWithCaching.SetValue(streamReader);
                }
                else
                {
                    // we are not in batch operation so we have to create it be able to read attachment's data
                    database.TransactionalStorage.Batch(accessor =>
                    {
                        var streamReader = new StreamReader(attachment.Data());
                        // we have to read it into memory because we after exiting the batch an attachment's data stream will be closed
                        fieldWithCaching.SetValue(streamReader.ReadToEnd());
                    });
                }

                yield return(fieldWithCaching);

                yield break;
            }
            if (Equals(value, string.Empty))
            {
                yield return(CreateFieldWithCaching(name, Constants.EmptyString, storage,
                                                    Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));

                yield break;
            }
            var dynamicNullObject = value as DynamicNullObject;

            if (ReferenceEquals(dynamicNullObject, null) == false)
            {
                if (dynamicNullObject.IsExplicitNull)
                {
                    var sortOptions = indexDefinition.GetSortOption(name, query: null);
                    if (sortOptions == null ||
                        sortOptions.Value == SortOptions.String ||
                        sortOptions.Value == SortOptions.None ||
                        sortOptions.Value == SortOptions.StringVal ||
                        sortOptions.Value == SortOptions.Custom)

                    {
                        yield return(CreateFieldWithCaching(name, Constants.NullValue, storage,
                                                            Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));
                    }

                    foreach (var field in CreateNumericFieldWithCaching(name, GetNullValueForSorting(sortOptions), storage, termVector))
                    {
                        yield return(field);
                    }
                }
                yield break;
            }
            var boostedValue = value as BoostedValue;

            if (boostedValue != null)
            {
                foreach (var field in CreateFields(name, boostedValue.Value, storage, false, termVector))
                {
                    field.Boost     = boostedValue.Boost;
                    field.OmitNorms = false;
                    yield return(field);
                }
                yield break;
            }


            var abstractField = value as AbstractField;

            if (abstractField != null)
            {
                yield return(abstractField);

                yield break;
            }
            var bytes = value as byte[];

            if (bytes != null)
            {
                yield return(CreateBinaryFieldWithCaching(name, bytes, storage, fieldIndexingOptions, termVector));

                yield break;
            }

            var itemsToIndex = value as IEnumerable;

            if (itemsToIndex != null && ShouldTreatAsEnumerable(itemsToIndex))
            {
                int count = 1;

                if (nestedArray == false)
                {
                    yield return(new Field(name + "_IsArray", "true", storage, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));
                }

                foreach (var itemToIndex in itemsToIndex)
                {
                    if (!CanCreateFieldsForNestedArray(itemToIndex, fieldIndexingOptions))
                    {
                        continue;
                    }

                    multipleItemsSameFieldCount.Add(count++);
                    foreach (var field in CreateFields(name, itemToIndex, storage, nestedArray: true, defaultTermVector: defaultTermVector, analyzed: analyzed))
                    {
                        yield return(field);
                    }

                    multipleItemsSameFieldCount.RemoveAt(multipleItemsSameFieldCount.Count - 1);
                }

                yield break;
            }

            if (Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED) ||
                Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED_NO_NORMS))                // explicitly not analyzed
            {
                // date time, time span and date time offset have the same structure fo analyzed and not analyzed.
                if (!(value is DateTime) && !(value is DateTimeOffset) && !(value is TimeSpan))
                {
                    yield return(CreateFieldWithCaching(name, value.ToString(), storage,
                                                        indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));

                    yield break;
                }
            }
            if (value is string)
            {
                var index = indexDefinition.GetIndex(name, Field.Index.ANALYZED);
                yield return(CreateFieldWithCaching(name, value.ToString(), storage, index, termVector));

                yield break;
            }

            if (value is TimeSpan)
            {
                var val = (TimeSpan)value;
                yield return(CreateFieldWithCaching(name, val.ToString("c", CultureInfo.InvariantCulture), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is DateTime)
            {
                var val          = (DateTime)value;
                var dateAsString = val.ToString(Default.DateTimeFormatsToWrite, CultureInfo.InvariantCulture);
                if (val.Kind == DateTimeKind.Utc)
                {
                    dateAsString += "Z";
                }
                yield return(CreateFieldWithCaching(name, dateAsString, storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is DateTimeOffset)
            {
                var val = (DateTimeOffset)value;

                string dtoStr;
                if (Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED) || Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED_NO_NORMS))
                {
                    dtoStr = val.ToString(Default.DateTimeOffsetFormatsToWrite, CultureInfo.InvariantCulture);
                }
                else
                {
                    dtoStr = val.UtcDateTime.ToString(Default.DateTimeFormatsToWrite, CultureInfo.InvariantCulture) + "Z";
                }
                yield return(CreateFieldWithCaching(name, dtoStr, storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is bool)
            {
                yield return(new Field(name, ((bool)value) ? "true" : "false", storage,
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is double)
            {
                var d = (double)value;
                yield return(CreateFieldWithCaching(name, d.ToString("r", CultureInfo.InvariantCulture), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is decimal)
            {
                var d = (decimal)value;
                var s = d.ToString(CultureInfo.InvariantCulture);
                if (s.Contains('.'))
                {
                    s = s.TrimEnd('0');
                    if (s.EndsWith("."))
                    {
                        s = s.Substring(0, s.Length - 1);
                    }
                }
                yield return(CreateFieldWithCaching(name, s, storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is Enum)
            {
                yield return(CreateFieldWithCaching(name, value.ToString(), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.ANALYZED_NO_NORMS), termVector));
            }
            else if (value is IConvertible)             // we need this to store numbers in invariant format, so JSON could read them
            {
                var convert = ((IConvertible)value);
                yield return(CreateFieldWithCaching(name, convert.ToString(CultureInfo.InvariantCulture), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is IDynamicJsonObject)
            {
                var inner = ((IDynamicJsonObject)value).Inner;
                yield return(CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));

                yield return(CreateFieldWithCaching(name, inner.ToString(Formatting.None), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else
            {
                var jsonVal = RavenJToken.FromObject(value).ToString(Formatting.None);
                if (jsonVal.StartsWith("{") || jsonVal.StartsWith("["))
                {
                    yield return(CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));
                }
                else if (jsonVal.StartsWith("\"") && jsonVal.EndsWith("\"") && jsonVal.Length > 1)
                {
                    jsonVal = jsonVal.Substring(1, jsonVal.Length - 2);
                }
                yield return(CreateFieldWithCaching(name, jsonVal, storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }


            foreach (var numericField in CreateNumericFieldWithCaching(name, value, storage, termVector))
            {
                yield return(numericField);
            }
        }
Example #8
0
        /// <summary>
        /// This method generate the fields for indexing documents in lucene from the values.
        /// Given a name and a value, it has the following behavior:
        /// * If the value is enumerable, index all the items in the enumerable under the same field name
        /// * If the value is null, create a single field with the supplied name with the unanalyzed value 'NULL_VALUE'
        /// * If the value is string or was set to not analyzed, create a single field with the supplied name
        /// * If the value is date, create a single field with millisecond precision with the supplied name
        /// * If the value is numeric (int, long, double, decimal, or float) will create two fields:
        ///		1. with the supplied name, containing the numeric value as an unanalyzed string - useful for direct queries
        ///		2. with the name: name +'_Range', containing the numeric value in a form that allows range queries
        /// </summary>
        public IEnumerable <AbstractField> CreateFields(string name, object value, Field.Store defaultStorage)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentException("Field must be not null, not empty and cannot contain whitespace", "name");
            }

            if (char.IsLetter(name[0]) == false &&
                name[0] != '_')
            {
                name = "_" + name;
            }

            var storage = indexDefinition.GetStorage(name, defaultStorage);

            if (value == null)
            {
                yield return(CreateFieldWithCaching(name, Constants.NullValue, storage,
                                                    Field.Index.NOT_ANALYZED_NO_NORMS));

                yield break;
            }
            if (Equals(value, string.Empty))
            {
                yield return(CreateFieldWithCaching(name, Constants.EmptyString, storage,
                                                    Field.Index.NOT_ANALYZED_NO_NORMS));

                yield break;
            }
            var dynamicNullObject = value as DynamicNullObject;

            if (ReferenceEquals(dynamicNullObject, null) == false)
            {
                if ((dynamicNullObject).IsExplicitNull)
                {
                    yield return(CreateFieldWithCaching(name, Constants.NullValue, storage,
                                                        Field.Index.NOT_ANALYZED_NO_NORMS));
                }
                yield break;
            }
            var boostedValue = value as BoostedValue;

            if (boostedValue != null)
            {
                foreach (var field in CreateFields(name, boostedValue.Value, storage))
                {
                    field.SetBoost(boostedValue.Boost);
                    field.SetOmitNorms(false);
                    yield return(field);
                }
                yield break;
            }

            var abstractField = value as AbstractField;

            if (abstractField != null)
            {
                yield return(abstractField);

                yield break;
            }
            var bytes = value as byte[];

            if (bytes != null)
            {
                yield return(CreateBinaryFieldWithCaching(name, bytes, storage));

                yield break;
            }

            var itemsToIndex = value as IEnumerable;

            if (itemsToIndex != null && ShouldTreatAsEnumerable(itemsToIndex))
            {
                yield return(new Field(name + "_IsArray", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

                int count = 1;
                foreach (var itemToIndex in itemsToIndex)
                {
                    multipleItemsSameFieldCount.Add(count++);
                    foreach (var field in CreateFields(name, itemToIndex, storage))
                    {
                        yield return(field);
                    }
                    multipleItemsSameFieldCount.RemoveAt(multipleItemsSameFieldCount.Count - 1);
                }
                yield break;
            }

            var fieldIndexingOptions = indexDefinition.GetIndex(name, null);

            if (fieldIndexingOptions == Field.Index.NOT_ANALYZED || fieldIndexingOptions == Field.Index.NOT_ANALYZED_NO_NORMS)            // explicitly not analyzed
            {
                if (value is DateTime)
                {
                    var val     = (DateTime)value;
                    var postFix = val.Kind == DateTimeKind.Utc ? "Z" : "";
                    yield return(CreateFieldWithCaching(name, val.ToString(Default.DateTimeFormatsToWrite) + postFix, storage,
                                                        indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
                }
                else if (value is DateTimeOffset)
                {
                    var val = (DateTimeOffset)value;
                    yield return(CreateFieldWithCaching(name, val.ToString(Default.DateTimeOffsetFormatsToWrite), storage,
                                                        indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
                }
                else
                {
                    yield return(CreateFieldWithCaching(name, value.ToString(), storage,
                                                        indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
                }
                yield break;
            }
            if (value is string)
            {
                var index = indexDefinition.GetIndex(name, Field.Index.ANALYZED);
                yield return(CreateFieldWithCaching(name, value.ToString(), storage,
                                                    index));

                yield break;
            }

            if (value is DateTime)
            {
                yield return(CreateFieldWithCaching(name, DateTools.DateToString((DateTime)value, DateTools.Resolution.MILLISECOND),
                                                    storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else if (value is DateTimeOffset)
            {
                yield return(CreateFieldWithCaching(name, DateTools.DateToString(((DateTimeOffset)value).UtcDateTime, DateTools.Resolution.MILLISECOND),
                                                    storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else if (value is bool)
            {
                yield return(new Field(name, ((bool)value) ? "true" : "false", storage,
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else if (value is IConvertible)            // we need this to store numbers in invariant format, so JSON could read them
            {
                var convert = ((IConvertible)value);
                yield return(CreateFieldWithCaching(name, convert.ToString(CultureInfo.InvariantCulture), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else if (value is IDynamicJsonObject)
            {
                var inner = ((IDynamicJsonObject)value).Inner;
                yield return(CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

                yield return(CreateFieldWithCaching(name, inner.ToString(), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }
            else
            {
                yield return(CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

                yield return(CreateFieldWithCaching(name, RavenJToken.FromObject(value).ToString(), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS)));
            }


            foreach (var numericField in CreateNumericFieldWithCaching(name, value, storage))
            {
                yield return(numericField);
            }
        }
        /// <summary>
        /// This method generate the fields for indexing documents in lucene from the values.
        /// Given a name and a value, it has the following behavior:
        /// * If the value is enumerable, index all the items in the enumerable under the same field name
        /// * If the value is null, create a single field with the supplied name with the unanalyzed value 'NULL_VALUE'
        /// * If the value is string or was set to not analyzed, create a single field with the supplied name
        /// * If the value is date, create a single field with millisecond precision with the supplied name
        /// * If the value is numeric (int, long, double, decimal, or float) will create two fields:
        ///		1. with the supplied name, containing the numeric value as an unanalyzed string - useful for direct queries
        ///		2. with the name: name +'_Range', containing the numeric value in a form that allows range queries
        /// </summary>
        private static IEnumerable <AbstractField> CreateFields(string name, object value, IndexDefinition indexDefinition, Field.Store defaultStorage)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentException("Field must be not null, not empty and cannot contain whitespace", "name");
            }

            if (char.IsLetter(name[0]) == false &&
                name[0] != '_')
            {
                name = "_" + name;
            }

            if (value == null)
            {
                yield return(new Field(name, Constants.NullValue, indexDefinition.GetStorage(name, defaultStorage),
                                       Field.Index.NOT_ANALYZED));

                yield break;
            }
            if (value is DynamicNullObject)
            {
                if (((DynamicNullObject)value).IsExplicitNull)
                {
                    yield return(new Field(name, Constants.NullValue, indexDefinition.GetStorage(name, defaultStorage),
                                           Field.Index.NOT_ANALYZED));
                }
                yield break;
            }

            if (value is AbstractField)
            {
                yield return((AbstractField)value);

                yield break;
            }


            var itemsToIndex = value as IEnumerable;

            if (itemsToIndex != null && ShouldTreatAsEnumerable(itemsToIndex))
            {
                yield return(new Field(name + "_IsArray", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

                foreach (var itemToIndex in itemsToIndex)
                {
                    foreach (var field in CreateFields(name, itemToIndex, indexDefinition, defaultStorage))
                    {
                        yield return(field);
                    }
                }
                yield break;
            }

            if (indexDefinition.GetIndex(name, null) == Field.Index.NOT_ANALYZED)// explicitly not analyzed
            {
                if (value is DateTime)
                {
                    var val = (DateTime)value;
                    yield return(new Field(name, val.ToString(Default.DateTimeFormatsToWrite), indexDefinition.GetStorage(name, defaultStorage),
                                           indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
                }
                else if (value is DateTimeOffset)
                {
                    var val = (DateTimeOffset)value;
                    yield return(new Field(name, val.ToString(Default.DateTimeFormatsToWrite), indexDefinition.GetStorage(name, defaultStorage),
                                           indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
                }
                else
                {
                    yield return(new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                           indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
                }
                yield break;
            }
            if (value is string)
            {
                var index = indexDefinition.GetIndex(name, Field.Index.ANALYZED);
                yield return(new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                       index));

                yield break;
            }

            if (value is DateTime)
            {
                yield return(new Field(name, DateTools.DateToString((DateTime)value, DateTools.Resolution.MILLISECOND),
                                       indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
            }
            else if (value is DateTimeOffset)
            {
                yield return(new Field(name, DateTools.DateToString(((DateTimeOffset)value).DateTime, DateTools.Resolution.MILLISECOND),
                                       indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
            }
            else if (value is bool)
            {
                yield return(new Field(name, ((bool)value) ? "true" : "false", indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
            }
            else if (value is IConvertible)            // we need this to store numbers in invariant format, so JSON could read them
            {
                var convert = ((IConvertible)value);
                yield return(new Field(name, convert.ToString(CultureInfo.InvariantCulture), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
            }
            else if (value is DynamicJsonObject)
            {
                var inner = ((DynamicJsonObject)value).Inner;
                yield return(new Field(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

                yield return(new Field(name, inner.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
            }
            else
            {
                yield return(new Field(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

                yield return(new Field(name, RavenJToken.FromObject(value).ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
            }


            var numericField = new NumericField(name + "_Range", indexDefinition.GetStorage(name, defaultStorage), true);

            if (value is int)
            {
                if (indexDefinition.GetSortOption(name) == SortOptions.Long)
                {
                    yield return(numericField.SetLongValue((int)value));
                }
                else
                {
                    yield return(numericField.SetIntValue((int)value));
                }
            }
            if (value is long)
            {
                yield return(numericField
                             .SetLongValue((long)value));
            }
            if (value is decimal)
            {
                yield return(numericField
                             .SetDoubleValue((double)(decimal)value));
            }
            if (value is float)
            {
                if (indexDefinition.GetSortOption(name) == SortOptions.Double)
                {
                    yield return(numericField.SetDoubleValue((float)value));
                }
                else
                {
                    yield return(numericField.SetFloatValue((float)value));
                }
            }
            if (value is double)
            {
                yield return(numericField
                             .SetDoubleValue((double)value));
            }
        }
		/// <summary>
		/// This method generate the fields for indexing documents in lucene from the values.
		/// Given a name and a value, it has the following behavior:
		/// * If the value is null, create a single field with the supplied name with the unanalyzed value 'NULL_VALUE'
		/// * If the value is string or was set to not analyzed, create a single field with the supplied name
		/// * If the value is date, create a single field with millisecond precision with the supplied name
		/// * If the value is numeric (int, long, double, decimal, or float) will create two fields:
		///		1. with the supplied name, containing the numeric value as an unanalyzed string - useful for direct queries
		///		2. with the name: name +'_Range', containing the numeric value in a form that allows range queries
		/// </summary>
		private static IEnumerable<AbstractField> Createfields(string name, object value, IndexDefinition indexDefinition, Field.Store defaultStorage)
		{
			if (value == null)
			{
				yield return new Field(name, "NULL_VALUE", indexDefinition.GetStorage(name, defaultStorage),
								 Field.Index.NOT_ANALYZED);
				yield break;
			}

			if (indexDefinition.GetIndex(name, Field.Index.ANALYZED) == Field.Index.NOT_ANALYZED || value is string)
			{
				yield return new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
								 indexDefinition.GetIndex(name, Field.Index.ANALYZED));
				yield break;
			}

			if (value is DateTime)
			{
				yield return new Field(name, DateTools.DateToString((DateTime)value, DateTools.Resolution.MILLISECOND),
					indexDefinition.GetStorage(name, defaultStorage),
					indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
			}
			else if(value is IConvertible) // we need this to store numbers in invariant format, so JSON could read them
			{
				var convert = ((IConvertible) value);
				yield return new Field(name, convert.ToString(CultureInfo.InvariantCulture), indexDefinition.GetStorage(name, defaultStorage),
				                       indexDefinition.GetIndex(name, GetDefaultIndexOption(value)));
			}
			else 
			{
				yield return new Field(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS);
				yield return new Field(name, JToken.FromObject(value).ToString(), indexDefinition.GetStorage(name, defaultStorage),
				                       indexDefinition.GetIndex(name, GetDefaultIndexOption(value)));
			}


			if (value is int)
			{
				yield return new Field(name +"_Range", NumberUtil.NumberToString((int)value), indexDefinition.GetStorage(name, defaultStorage),
							 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));

			}
			if (value is long)
			{
				yield return new Field(name + "_Range", NumberUtil.NumberToString((long)value), indexDefinition.GetStorage(name, defaultStorage),
							 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));

			}
			if (value is decimal)
            {
				yield return new Field(name + "_Range", NumberUtil.NumberToString((double)(decimal)value), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
            }
			if (value is float)
            {
				yield return new Field(name + "_Range", NumberUtil.NumberToString((float)value), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
            }
			if (value is double)
            {
				yield return new Field(name + "_Range", NumberUtil.NumberToString((double)value), indexDefinition.GetStorage(name, defaultStorage),
                                 indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED));
            }
		}
        /// <summary>
        /// This method generate the fields for indexing documents in lucene from the values.
        /// Given a name and a value, it has the following behavior:
        /// * If the value is null, create a single field with the supplied name with the unanalyzed value 'NULL_VALUE'
        /// * If the value is string or was set to not analyzed, create a single field with the supplied name
        /// * If the value is date, create a single field with millisecond precision with the supplied name
        /// * If the value is numeric (int, long, double, decimal, or float) will create two fields:
        ///		1. with the supplied name, containing the numeric value as an unanalyzed string - useful for direct queries
        ///		2. with the name: name +'_Range', containing the numeric value in a form that allows range queries
        /// </summary>
        private static IEnumerable <AbstractField> CreateFields(string name, object value, IndexDefinition indexDefinition, Field.Store defaultStorage)
        {
            if (value == null)
            {
                yield return(new Field(name, "NULL_VALUE", indexDefinition.GetStorage(name, defaultStorage),
                                       Field.Index.NOT_ANALYZED));

                yield break;
            }

            if (indexDefinition.GetIndex(name, Field.Index.ANALYZED) == Field.Index.NOT_ANALYZED || value is string)
            {
                yield return(new Field(name, value.ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.ANALYZED)));

                yield break;
            }

            if (value is DateTime)
            {
                yield return(new Field(name, DateTools.DateToString((DateTime)value, DateTools.Resolution.MILLISECOND),
                                       indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED)));
            }
            else if (value is IConvertible)            // we need this to store numbers in invariant format, so JSON could read them
            {
                var convert = ((IConvertible)value);
                yield return(new Field(name, convert.ToString(CultureInfo.InvariantCulture), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, GetDefaultIndexOption(value))));
            }
            else
            {
                yield return(new Field(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

                yield return(new Field(name, JToken.FromObject(value).ToString(), indexDefinition.GetStorage(name, defaultStorage),
                                       indexDefinition.GetIndex(name, GetDefaultIndexOption(value))));
            }


            if (value is int)
            {
                yield return(new NumericField(name + "_Range", indexDefinition.GetStorage(name, defaultStorage), true)
                             .SetIntValue((int)value));
            }
            if (value is long)
            {
                yield return(new NumericField(name + "_Range", indexDefinition.GetStorage(name, defaultStorage), true)
                             .SetLongValue((long)value));
            }
            if (value is decimal)
            {
                yield return(new NumericField(name + "_Range", indexDefinition.GetStorage(name, defaultStorage), true)
                             .SetDoubleValue((double)(decimal)value));
            }
            if (value is float)
            {
                yield return(new NumericField(name + "_Range", indexDefinition.GetStorage(name, defaultStorage), true)
                             .SetFloatValue((float)value));
            }
            if (value is double)
            {
                yield return(new NumericField(name + "_Range", indexDefinition.GetStorage(name, defaultStorage), true)
                             .SetDoubleValue((double)value));
            }
        }
Example #12
0
        private IEnumerable <AbstractField> CreateRegularFields(string name, object value, Field.Store defaultStorage, bool nestedArray = false, Field.TermVector defaultTermVector = Field.TermVector.NO)
        {
            var fieldIndexingOptions = indexDefinition.GetIndex(name, null);
            var storage    = indexDefinition.GetStorage(name, defaultStorage);
            var termVector = indexDefinition.GetTermVector(name, defaultTermVector);

            if (fieldIndexingOptions == Field.Index.NO && storage == Field.Store.NO && termVector == Field.TermVector.NO)
            {
                yield break;
            }

            if (fieldIndexingOptions == Field.Index.NO && storage == Field.Store.NO)
            {
                fieldIndexingOptions = Field.Index.ANALYZED;                 // we have some sort of term vector, forcing index to be analyzed, then.
            }


            if (value == null)
            {
                yield return(CreateFieldWithCaching(name, Constants.NullValue, storage,
                                                    Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));

                yield break;
            }
            if (Equals(value, string.Empty))
            {
                yield return(CreateFieldWithCaching(name, Constants.EmptyString, storage,
                                                    Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));

                yield break;
            }
            if (value is DynamicNullObject)
            {
                if (((DynamicNullObject)value).IsExplicitNull)
                {
                    var sortOptions = indexDefinition.GetSortOption(name);
                    if (sortOptions != null && sortOptions.Value != SortOptions.None)
                    {
                        yield break;                         // we don't emit null for sorting
                    }
                    yield return(CreateFieldWithCaching(name, Constants.NullValue, storage,
                                                        Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));
                }
                yield break;
            }
            var boostedValue = value as BoostedValue;

            if (boostedValue != null)
            {
                foreach (var field in CreateFields(name, boostedValue.Value, storage, false, termVector))
                {
                    field.Boost     = boostedValue.Boost;
                    field.OmitNorms = false;
                    yield return(field);
                }
                yield break;
            }


            var abstractField = value as AbstractField;

            if (abstractField != null)
            {
                yield return(abstractField);

                yield break;
            }
            var bytes = value as byte[];

            if (bytes != null)
            {
                yield return(CreateBinaryFieldWithCaching(name, bytes, storage, fieldIndexingOptions, termVector));

                yield break;
            }

            var itemsToIndex = value as IEnumerable;

            if (itemsToIndex != null && ShouldTreatAsEnumerable(itemsToIndex))
            {
                var sentArrayField = false;
                int count          = 1;
                foreach (var itemToIndex in itemsToIndex)
                {
                    if (nestedArray == false && !Equals(storage, Field.Store.NO) && sentArrayField == false)
                    {
                        sentArrayField = true;
                        yield return(new Field(name + "_IsArray", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));
                    }

                    if (CanCreateFieldsForNestedArray(itemToIndex, fieldIndexingOptions))
                    {
                        multipleItemsSameFieldCount.Add(count++);
                        foreach (var field in CreateFields(name, itemToIndex, storage, nestedArray: true))
                        {
                            yield return(field);
                        }
                        multipleItemsSameFieldCount.RemoveAt(multipleItemsSameFieldCount.Count - 1);
                    }
                }
                yield break;
            }

            if (Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED) ||
                Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED_NO_NORMS))                // explicitly not analyzed
            {
                // date time, time span and date time offset have the same structure fo analyzed and not analyzed.
                if (!(value is DateTime) && !(value is DateTimeOffset) && !(value is TimeSpan))
                {
                    yield return(CreateFieldWithCaching(name, value.ToString(), storage,
                                                        indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));

                    yield break;
                }
            }
            if (value is string)
            {
                var index = indexDefinition.GetIndex(name, Field.Index.ANALYZED);
                yield return(CreateFieldWithCaching(name, value.ToString(), storage, index, termVector));

                yield break;
            }

            if (value is TimeSpan)
            {
                var val = (TimeSpan)value;
                yield return(CreateFieldWithCaching(name, val.ToString("c", CultureInfo.InvariantCulture), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is DateTime)
            {
                var val          = (DateTime)value;
                var dateAsString = val.ToString(Default.DateTimeFormatsToWrite);
                if (val.Kind == DateTimeKind.Utc)
                {
                    dateAsString += "Z";
                }
                yield return(CreateFieldWithCaching(name, dateAsString, storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is DateTimeOffset)
            {
                var val = (DateTimeOffset)value;

                string dtoStr;
                if (Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED) || Equals(fieldIndexingOptions, Field.Index.NOT_ANALYZED_NO_NORMS))
                {
                    dtoStr = val.ToString(Default.DateTimeOffsetFormatsToWrite);
                }
                else
                {
                    dtoStr = val.UtcDateTime.ToString(Default.DateTimeFormatsToWrite) + "Z";
                }
                yield return(CreateFieldWithCaching(name, dtoStr, storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is bool)
            {
                yield return(new Field(name, ((bool)value) ? "true" : "false", storage,
                                       indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is double)
            {
                var d = (double)value;
                yield return(CreateFieldWithCaching(name, d.ToString("r", CultureInfo.InvariantCulture), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is decimal)
            {
                var d = (decimal)value;
                var s = d.ToString(CultureInfo.InvariantCulture);
                if (s.Contains('.'))
                {
                    s = s.TrimEnd('0');
                    if (s.EndsWith("."))
                    {
                        s = s.Substring(0, s.Length - 1);
                    }
                }
                yield return(CreateFieldWithCaching(name, s, storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is IConvertible)             // we need this to store numbers in invariant format, so JSON could read them
            {
                var convert = ((IConvertible)value);
                yield return(CreateFieldWithCaching(name, convert.ToString(CultureInfo.InvariantCulture), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else if (value is IDynamicJsonObject)
            {
                var inner = ((IDynamicJsonObject)value).Inner;
                yield return(CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));

                yield return(CreateFieldWithCaching(name, inner.ToString(Formatting.None), storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }
            else
            {
                var jsonVal = RavenJToken.FromObject(value).ToString(Formatting.None);
                if (jsonVal.StartsWith("{") || jsonVal.StartsWith("["))
                {
                    yield return(CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));
                }
                else if (jsonVal.StartsWith("\"") && jsonVal.EndsWith("\"") && jsonVal.Length > 1)
                {
                    jsonVal = jsonVal.Substring(1, jsonVal.Length - 2);
                }
                yield return(CreateFieldWithCaching(name, jsonVal, storage,
                                                    indexDefinition.GetIndex(name, Field.Index.NOT_ANALYZED_NO_NORMS), termVector));
            }


            foreach (var numericField in CreateNumericFieldWithCaching(name, value, storage, termVector))
            {
                yield return(numericField);
            }
        }