Example #1
0
        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.GetDefaultRavenFormat();
                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.GetDefaultRavenFormat(true);
                }
                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);
            }
        }
        /// <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, Field.TermVector defaultTermVector = Field.TermVector.NO)
        {
            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);
            var termVector = indexDefinition.GetTermVector(name, defaultTermVector);

            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 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
            {
                yield return(CreateFieldWithCaching(name + "_ConvertToJson", "true", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));

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


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