<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Threading;
using System.Xml;
using ExRam.Gremlinq;
using Newtonsoft.Json.Linq;

namespace Microsoft.Azure.Documents.Client
{
    public static class CosmosDbSessionExtensions
    {
        private sealed class DocumentClientGremlinQueryProvider : INativeGremlinQueryProvider
        {
            private readonly ICosmosDbSession _session;

            public DocumentClientGremlinQueryProvider(ICosmosDbSession session)
            {
                this._session = session;
                this.TraversalSource = GremlinQuery.Create("g");
            }

            public IAsyncEnumerable<string> Execute(string query, IDictionary<string, object> parameters)
            {
                foreach(var kvp in parameters.OrderByDescending(x => x.Key.Length))
                {
                    var value = kvp.Value;

                    if (value is Enum)
                        value = (int)value;
                    else if (value is DateTimeOffset)
                        value = ((DateTimeOffset)value).ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz");
                    else if (value is DateTime)
                        value = ((DateTime)value).ToUniversalTime().ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffZ");
                    else if (value is TimeSpan)
                        value = XmlConvert.ToString((TimeSpan)value);

                    if (value is string)
                        value = $"'{value}'";
                    else
                        value = value.ToString().ToLower();

                    query = query.Replace(kvp.Key, (string)value);
                }

                Console.WriteLine(query);

                var documentQuery = this._session.CreateGremlinQuery<JToken>(query);

                return AsyncEnumerable
                    .Repeat(Unit.Default)
                    .TakeWhile(_ => documentQuery.HasMoreResults)
                    .SelectMany(async (_, ct) =>
                    {
                        try
                        {
                            return await documentQuery.ExecuteNextAsync<JToken>(ct).ConfigureAwait(false);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception(query, ex);
                        }
                    })
                    .SelectMany(x => x.ToAsyncEnumerable())
                    .Select(x => x.ToString());
            }

            public IGremlinQuery<Unit> TraversalSource { get; }
        }

        public static INativeGremlinQueryProvider CreateQueryProvider(this ICosmosDbSession session)
        {
            return new DocumentClientGremlinQueryProvider(session);
        }
    }
}
<commit_msg>Support byte-Arrays in Gremlin-Queries on CosmosDB.<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Threading;
using System.Xml;
using ExRam.Gremlinq;
using Newtonsoft.Json.Linq;

namespace Microsoft.Azure.Documents.Client
{
    public static class CosmosDbSessionExtensions
    {
        private sealed class DocumentClientGremlinQueryProvider : INativeGremlinQueryProvider
        {
            private readonly ICosmosDbSession _session;

            public DocumentClientGremlinQueryProvider(ICosmosDbSession session)
            {
                this._session = session;
                this.TraversalSource = GremlinQuery.Create("g");
            }

            public IAsyncEnumerable<string> Execute(string query, IDictionary<string, object> parameters)
            {
                foreach(var kvp in parameters.OrderByDescending(x => x.Key.Length))
                {
                    var value = kvp.Value;

                    if (value is Enum)
                        value = (int)value;
                    else if (value is DateTimeOffset)
                        value = ((DateTimeOffset)value).ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz");
                    else if (value is DateTime)
                        value = ((DateTime)value).ToUniversalTime().ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffZ");
                    else if (value is TimeSpan)
                        value = XmlConvert.ToString((TimeSpan)value);
                    else if (value is byte[])
                        value = Convert.ToBase64String((byte[])value);

                    if (value is string)
                        value = $"'{value}'";
                    else
                        value = value.ToString().ToLower();

                    query = query.Replace(kvp.Key, (string)value);
                }

                Console.WriteLine(query);

                var documentQuery = this._session.CreateGremlinQuery<JToken>(query);

                return AsyncEnumerable
                    .Repeat(Unit.Default)
                    .TakeWhile(_ => documentQuery.HasMoreResults)
                    .SelectMany(async (_, ct) =>
                    {
                        try
                        {
                            return await documentQuery.ExecuteNextAsync<JToken>(ct).ConfigureAwait(false);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception(query, ex);
                        }
                    })
                    .SelectMany(x => x.ToAsyncEnumerable())
                    .Select(x => x.ToString());
            }

            public IGremlinQuery<Unit> TraversalSource { get; }
        }

        public static INativeGremlinQueryProvider CreateQueryProvider(this ICosmosDbSession session)
        {
            return new DocumentClientGremlinQueryProvider(session);
        }
    }
}

{'fraction_non_alphanumeric': 0.08523018997090535, 'fraction_numerical': 0.0003422899195618689, 'mean_word_length': 1.4188741721854305, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3427654', 'n_tokens_mistral': 1440, 'n_tokens_neox': 1314, 'n_words': 274}