public async Task Test_FdbMap_With_Custom_Key_Encoder()
        {
            // Use a table as a backing store for the rules of a Poor Man's firewall, where each keys are the IPEndPoint (tcp only!), and the values are "pass" or "block"

            // Encode IPEndPoint as the (IP, Port,) encoded with the Tuple codec
            // note: there is a much simpler way or creating composite keys, this is just a quick and dirty test!
            var keyEncoder = KeyValueEncoders.Bind <IPEndPoint>(
                (ipe) => ipe == null ? Slice.Empty : FdbTuple.EncodeKey(ipe.Address, ipe.Port),
                (packed) =>
            {
                if (packed.IsNullOrEmpty)
                {
                    return(default(IPEndPoint));
                }
                var t = FdbTuple.Unpack(packed);
                return(new IPEndPoint(t.Get <IPAddress>(0), t.Get <int>(1)));
            }
                );

            var rules = new Dictionary <IPEndPoint, string>()
            {
                { new IPEndPoint(IPAddress.Parse("172.16.12.34"), 6667), "block" },
                { new IPEndPoint(IPAddress.Parse("192.168.34.56"), 80), "pass" },
                { new IPEndPoint(IPAddress.Parse("192.168.34.56"), 443), "pass" }
            };

            using (var db = await OpenTestPartitionAsync())
            {
                var location = await GetCleanDirectory(db, "Collections", "Maps");

                var map = new FdbMap <IPEndPoint, string>("Firewall", location.Partition.ByKey("Hosts"), keyEncoder, KeyValueEncoders.Values.StringEncoder);

                // import all the rules
                await db.WriteAsync((tr) =>
                {
                    foreach (var rule in rules)
                    {
                        map.Set(tr, rule.Key, rule.Value);
                    }
                }, this.Cancellation);

#if DEBUG
                await DumpSubspace(db, location);
#endif

                // test the rules

                using (var tr = db.BeginTransaction(this.Cancellation))
                {
                    var value = await map.GetAsync(tr, new IPEndPoint(IPAddress.Parse("172.16.12.34"), 6667));

                    Assert.That(value, Is.EqualTo("block"));

                    value = await map.GetAsync(tr, new IPEndPoint(IPAddress.Parse("192.168.34.56"), 443));

                    Assert.That(value, Is.EqualTo("pass"));

                    var baz = new IPEndPoint(IPAddress.Parse("172.16.12.34"), 80);
                    Assert.That(async() => await map.GetAsync(tr, baz), Throws.InstanceOf <KeyNotFoundException>());

                    var opt = await map.TryGetAsync(tr, baz);

                    Assert.That(opt.HasValue, Is.False);
                }
            }
        }
        public async Task Test_Range_Except()
        {
            int K = 3;
            int N = 100;

            using (var db = await OpenTestPartitionAsync())
            {
                // get a clean new directory
                var location = await GetCleanDirectory(db, "Queries", "Except");

                // create K lists
                var lists = Enumerable.Range(0, K).Select(i => location.Partition.ByKey(i)).ToArray();

                // lists[0] contains all multiples of 1
                // lists[1] contains all multiples of 2
                // lists[k-1] contains all multiples of K

                // more generally: lists[k][i] = (..., Intersect, k, i * (k + 1)) = (k, i)

                var series = Enumerable.Range(1, K).Select(k => Enumerable.Range(1, N).Select(x => k * x).ToArray()).ToArray();
                //foreach(var serie in series)
                //{
                //	Console.WriteLine(String.Join(", ", serie));
                //}

                for (int k = 0; k < K; k++)
                {
                    //Console.WriteLine("> k = " + k);
                    using (var tr = db.BeginTransaction(this.Cancellation))
                    {
                        for (int i = 0; i < N; i++)
                        {
                            var key   = lists[k].Keys.Encode(series[k][i]);
                            var value = FdbTuple.EncodeKey(k, i);
                            //Console.WriteLine("> " + key + " = " + value);
                            tr.Set(key, value);
                        }
                        await tr.CommitAsync();
                    }
                }

                // Intersect all lists together should produce all integers that are prime numbers
                IEnumerable <int> xs = series[0];
                for (int i = 1; i < K; i++)
                {
                    xs = xs.Except(series[i]);
                }
                var expected = xs.ToArray();
                Log("Expected: {0}", String.Join(", ", expected));

                using (var tr = db.BeginTransaction(this.Cancellation))
                {
                    var merge = tr.Except(
                        lists.Select(list => FdbKeySelectorPair.Create(list.Keys.ToRange())),
                        kvp => location.Keys.DecodeLast <int>(kvp.Key)
                        );

                    Assert.That(merge, Is.Not.Null);
                    Assert.That(merge, Is.InstanceOf <FdbExceptIterator <KeyValuePair <Slice, Slice>, int, KeyValuePair <Slice, Slice> > >());

                    var results = await merge.ToListAsync();

                    Assert.That(results, Is.Not.Null);

                    Assert.That(results.Count, Is.EqualTo(expected.Length));

                    for (int i = 0; i < results.Count; i++)
                    {
                        Assert.That(location.Keys.DecodeLast <int>(results[i].Key), Is.EqualTo(expected[i]));
                    }
                }
            }
        }
 public Slice EncodeValue(T key)
 {
     return(FdbTuple.EncodeKey(key));
 }