// constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="ReadPreference" /> class.
        /// </summary>
        /// <param name="mode">The read preference mode.</param>
        /// <param name="tagSets">The tag sets.</param>
        /// <param name="maxStaleness">The maximum staleness.</param>
        /// <param name="hedge">The hedge.</param>
        public ReadPreference(
            ReadPreferenceMode mode,
            IEnumerable <TagSet> tagSets = null,
            TimeSpan?maxStaleness        = null,
            ReadPreferenceHedge hedge    = null)
        {
            var tagSetsArray = tagSets == null ? __emptyTagSetsArray : tagSets.ToArray();

            if (tagSetsArray.Length > 0)
            {
                Ensure.That(mode != ReadPreferenceMode.Primary, "TagSets cannot be used with ReadPreferenceMode Primary.", nameof(tagSets));
            }

            if (maxStaleness.HasValue)
            {
                Ensure.IsInfiniteOrGreaterThanZero(maxStaleness.Value, nameof(maxStaleness));
                if (maxStaleness.Value > TimeSpan.Zero)
                {
                    Ensure.That(maxStaleness.Value.Ticks % TimeSpan.TicksPerMillisecond == 0, "MaxStaleness must not have fractional seconds.", nameof(maxStaleness));
                }
                Ensure.That(mode != ReadPreferenceMode.Primary, "MaxStaleness cannot be used with ReadPreferenceMode Primary.", nameof(maxStaleness));
            }

            if (hedge != null)
            {
                Ensure.That(mode != ReadPreferenceMode.Primary, "Hedged reads cannot be used with ReadPreferenceMode Primary.", nameof(hedge));
            }

            _mode         = mode;
            _tagSets      = tagSetsArray;
            _maxStaleness = maxStaleness;
            _hedge        = hedge;
        }
        public void constructor_should_throw_when_hedge_is_not_null_and_mode_is_primary()
        {
            var hedge = new ReadPreferenceHedge(true);

            var exception = Record.Exception(() => new ReadPreference(ReadPreferenceMode.Primary, hedge: hedge));

            var argumentException = exception.Should().BeOfType <ArgumentException>().Subject;

            argumentException.ParamName.Should().Be("hedge");
        }
        // public static methods
        /// <summary>
        /// Creates a new ReadPreference instance from a BsonDocument.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <returns>A ReadPreference.</returns>
        public static ReadPreference FromBsonDocument(BsonDocument document)
        {
            ReadPreferenceMode  mode         = ReadPreferenceMode.Primary;
            TimeSpan?           maxStaleness = null;
            List <TagSet>       tagSets      = null;
            ReadPreferenceHedge hedge        = null;

            foreach (var element in document)
            {
                switch (element.Name)
                {
                case "mode":
                    mode = (ReadPreferenceMode)Enum.Parse(typeof(ReadPreferenceMode), element.Value.AsString, ignoreCase: true);
                    break;

                case "tags":
                    tagSets = new List <TagSet>();
                    foreach (var tagsDocument in element.Value.AsBsonArray.Cast <BsonDocument>())
                    {
                        var tags = new List <Tag>();
                        foreach (var tagElement in tagsDocument)
                        {
                            var tag = new Tag(tagElement.Name, tagElement.Value.AsString);
                            tags.Add(tag);
                        }
                        var tagSet = new TagSet(tags);
                        tagSets.Add(tagSet);
                    }
                    break;

                case "maxStaleness":
                    maxStaleness = element.Value.BsonType switch
                    {
                        BsonType.String => TimeSpanParser.Parse(element.Value.AsString),
                        _ => TimeSpan.FromSeconds(element.Value.ToDouble())
                    };
                    break;

                case "maxStalenessSeconds":
                    maxStaleness = TimeSpan.FromSeconds(element.Value.ToDouble());
                    break;

                case "hedge":
                    var hedgeEnabled = element.Value.AsBsonDocument["enabled"].AsBoolean;
                    hedge = new ReadPreferenceHedge(hedgeEnabled);
                    break;

                default:
                    throw new ArgumentException($"Invalid element in ReadPreference document: {element.Name}.");
                }
            }

            return(new ReadPreference(mode, tagSets, maxStaleness, hedge));
        }
        public void With_hedge_should_return_expected_result(
            [Values(false, true)]
            bool originalIsEnabled,
            [Values(false, true)]
            bool isEnabled)
        {
            var originalHedge = new ReadPreferenceHedge(isEnabled: originalIsEnabled);
            var hedge         = new ReadPreferenceHedge(isEnabled: isEnabled);
            var subject       = new ReadPreference(ReadPreferenceMode.Secondary, hedge: originalHedge);

            var result = subject.With(hedge);

            result.Hedge.Should().Be(hedge);
            result.With(originalHedge).Should().Be(subject);
        }
 /// <summary>
 /// Returns a new instance of ReadPreference with some values changed.
 /// </summary>
 /// <param name="hedge">The hedge.</param>
 /// <returns>A new instance of ReadPreference.</returns>
 public ReadPreference With(ReadPreferenceHedge hedge)
 {
     return(new ReadPreference(_mode, _tagSets, _maxStaleness, hedge));
 }