[
  {
    "path": ".gitignore",
    "content": "# Created by https://www.gitignore.io/api/visualstudio\n\nnuget.exe\nnuget/\n### VisualStudio ###\n## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n"
  },
  {
    "path": "CONTRIBUTORS.md",
    "content": "# Contributors\n\n* [Joash Chong](https://github.com/joashc) - Author\n* [Courtney Strachan](https://github.com/cstrachan88)"
  },
  {
    "path": "HaxlSharp.Core/BlockedRequest.cs",
    "content": "﻿using System;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp\r\n{\r\n    /// <summary>\r\n    /// A request that's blocking the completion of a fetch.\r\n    /// </summary>\r\n    /// <remarks>\r\n    /// We simulate existential types by packaging the request with its type information.\r\n    /// </remarks>\r\n    public class BlockedRequest\r\n    {\r\n        public readonly object TypedRequest;\r\n        public readonly Type RequestType;\r\n        public readonly string BindName;\r\n        public readonly TaskCompletionSource<object> Resolver;\r\n\r\n        public BlockedRequest(object typedRequest, Type requestType, string bindName)\r\n        {\r\n            TypedRequest = typedRequest;\r\n            RequestType = requestType;\r\n            BindName = bindName;\r\n            Resolver = new TaskCompletionSource<object>();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/CacheKeyGenerator.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp\r\n{\r\n    /// <summary>\r\n    /// Generates a unique key per request.\r\n    /// </summary>\r\n    public interface CacheKeyGenerator\r\n    {\r\n        string ForRequest<A>(Returns<A> request);\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Fetch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel;\r\nusing System.Linq;\r\nusing System.Linq.Expressions;\r\nusing System.Threading.Tasks;\r\nusing static HaxlSharp.Internal.Base;\r\nusing HaxlSharp.Internal;\r\nusing System.Diagnostics;\r\n\r\nnamespace HaxlSharp\r\n{\r\n    /// <summary>\r\n    /// Fetch a result.\r\n    /// </summary>\r\n    /// <fetch>\r\n    /// This is a free monad that leaves its expression tree open for inspection.\r\n    /// </fetch>\r\n    public interface Fetch<A> : Fetchable\r\n    {\r\n        [EditorBrowsable(EditorBrowsableState.Never)]\r\n        IEnumerable<BindProjectPair> CollectedExpressions { get; }\r\n\r\n        [EditorBrowsable(EditorBrowsableState.Never)]\r\n        LambdaExpression Initial { get; }\r\n    }\r\n\r\n    public interface Fetchable\r\n    {\r\n        [EditorBrowsable(EditorBrowsableState.Never)]\r\n        Haxl ToHaxlFetch(string bindTo, Scope scope);\r\n    }\r\n\r\n    /// <summary>\r\n    /// Monadic bind that just collects the query expression tree for inspection.\r\n    /// </summary>\r\n    [EditorBrowsable(EditorBrowsableState.Never)]\r\n    public class Bind<A, B, C> : Fetch<C>\r\n    {\r\n        public IEnumerable<BindProjectPair> CollectedExpressions { get; }\r\n\r\n        public readonly Fetch<A> Fetch;\r\n        public bool IsLet;\r\n\r\n        public Bind(IEnumerable<BindProjectPair> binds, Fetch<A> expr)\r\n        {\r\n            CollectedExpressions = binds;\r\n            Fetch = expr;\r\n        }\r\n\r\n        public LambdaExpression Initial => Fetch.Initial;\r\n\r\n        public Haxl ToHaxlFetch(string bindTo, Scope scope)\r\n        {\r\n            var bindSplit = SplitApplicative.SplitBind(CollectedExpressions, Initial);\r\n            var newScope = IsLet ? scope : new Scope(scope);\r\n            return HaxlApplicative.ToFetch(bindSplit, bindTo, newScope);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// All binds must terminate in a FetchNode.\r\n    /// </summary>\r\n    public abstract class FetchNode<A> : Fetch<A>\r\n    {\r\n        private static readonly IEnumerable<BindProjectPair> emptyList = new List<BindProjectPair>();\r\n        public IEnumerable<BindProjectPair> CollectedExpressions => emptyList;\r\n        public LambdaExpression Initial => Expression.Lambda(Expression.Constant(this));\r\n        public abstract Haxl ToHaxlFetch(string bindTo, Scope scope);\r\n    }\r\n\r\n    /// <summary>\r\n    /// Wraps a primitive request type.\r\n    /// </summary>\r\n    [EditorBrowsable(EditorBrowsableState.Never)]\r\n    public class Request<A> : FetchNode<A>\r\n    {\r\n        public readonly Returns<A> request;\r\n        public Request(Returns<A> request)\r\n        {\r\n            this.request = request;\r\n        }\r\n\r\n        public object WarnIfNull(object result, Action<HaxlLogEntry> logger)\r\n        {\r\n            if (result == null) logger(Warn($\"The request type '{request.GetType().Name}' returned a null.\"));\r\n            return result;\r\n        }\r\n\r\n        public override Haxl ToHaxlFetch(string bindTo, Scope scope)\r\n        {\r\n            Func<Task<object>, Haxl> DoneFromTask =\r\n                t => Haxl.FromFunc((c, l) => Done.New(_ => scope.Add(bindTo, WarnIfNull(t.Result, l))));\r\n\r\n            return Haxl.FromFunc((cache, logger) =>\r\n            {\r\n                var cacheResult = cache.Lookup(request);\r\n                return cacheResult.Match<Result>\r\n                    (\r\n                        notFound =>\r\n                        {\r\n                            var blocked = new BlockedRequest(request, request.GetType(), bindTo);\r\n                            cache.Insert(request, blocked);\r\n                            return Blocked.New(\r\n                                new List<BlockedRequest> { blocked },\r\n                                DoneFromTask(blocked.Resolver.Task)\r\n                            );\r\n                        },\r\n                        found =>\r\n                        {\r\n                            var task = found.Resolver.Task;\r\n                            if (task.IsCompleted)\r\n                                return Done.New(_ =>\r\n                                {\r\n                                    var result = task.Result;\r\n                                    return scope.Add(bindTo, WarnIfNull(result, logger));\r\n                                });\r\n                            return Blocked.New(\r\n                                new List<BlockedRequest>(),\r\n                                DoneFromTask(task)\r\n                            );\r\n                        }\r\n                    );\r\n            });\r\n        }\r\n\r\n        public Type RequestType => request.GetType();\r\n    }\r\n\r\n    /// <summary>\r\n    /// Applicative sequence.\r\n    /// </summary>\r\n    [EditorBrowsable(EditorBrowsableState.Never)]\r\n    public class RequestSequence<A, B> : FetchNode<IEnumerable<B>>\r\n    {\r\n        public readonly IEnumerable<A> List;\r\n        public readonly Func<A, Fetch<B>> Bind;\r\n        public RequestSequence(IEnumerable<A> list, Func<A, Fetch<B>> bind)\r\n        {\r\n            List = list;\r\n            Bind = bind;\r\n        }\r\n\r\n        public override Haxl ToHaxlFetch(string bindTo, Scope parentScope)\r\n        {\r\n            var childScope = new Scope(parentScope);\r\n            var binds = List.Select(Bind).ToList();\r\n            var fetches = binds.Select((f, i) => f.ToHaxlFetch($\"{bindTo}[{i}]\", childScope)).ToList();\r\n            var concurrent = fetches.Aggregate((f1, f2) => f1.Applicative(f2));\r\n            return concurrent.Bind(scope => Haxl.FromFunc((cache, logger) => Done.New(_ =>\r\n            {\r\n                var values = scope.ShallowValues.Select(v => (B)v).ToList();\r\n                return scope.WriteParent(bindTo, values);\r\n            }\r\n            )));\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// Wraps the value in a Fetch monad.\r\n    /// </summary>\r\n    [EditorBrowsable(EditorBrowsableState.Never)]\r\n    public class FetchResult<A> : FetchNode<A>\r\n    {\r\n        public readonly A Value;\r\n\r\n        public FetchResult(A value)\r\n        {\r\n            Value = value;\r\n        }\r\n\r\n        public override Haxl ToHaxlFetch(string bindTo, Scope scope)\r\n        {\r\n            return Haxl.FromFunc((cache, logger) => Done.New(_ => scope.Add(bindTo, Value)));\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// Maps the result of the fetch with given function.\r\n    /// </summary>\r\n    [EditorBrowsable(EditorBrowsableState.Never)]\r\n    public class Select<A, B> : FetchNode<B>\r\n    {\r\n        public readonly Fetch<A> Fetch;\r\n        public readonly Expression<Func<A, B>> Map;\r\n        public Select(Fetch<A> fetch, Expression<Func<A, B>> map)\r\n        {\r\n            Fetch = fetch;\r\n            Map = map;\r\n        }\r\n\r\n        public override Haxl ToHaxlFetch(string bindTo, Scope parentScope)\r\n        {\r\n            return Fetch.ToHaxlFetch(bindTo, parentScope).Map(scope =>\r\n            {\r\n                var newScope = scope;\r\n                if (scope.InScope(bindTo))\r\n                {\r\n                    var value = scope.GetValue(bindTo);\r\n                    newScope = new SelectScope(value, scope);\r\n                }\r\n\r\n                var blockNumber = newScope.GetLatestBlockNumber();\r\n                var rebinder = new RebindToScope() { BlockCount = blockNumber };\r\n                var rewritten = rebinder.Rebind(Map);\r\n                return scope.Add(bindTo, rewritten.Compile().DynamicInvoke(newScope));\r\n            });\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// Monad instance for Fetch.\r\n    /// </summary>\r\n    public static class ExprExt\r\n    {\r\n        public static Fetch<B> Select<A, B>(this Fetch<A> self, Expression<Func<A, B>> f)\r\n        {\r\n            var isLet = LetExpression.IsLetExpression(f);\r\n            if (!isLet) return new Select<A, B>(self, f);\r\n\r\n            Expression<Func<A, Fetch<A>>> letBind = _ => self;\r\n            var letProject = LetExpression.RewriteLetExpression(f);\r\n            var letPair = new BindProjectPair(letBind, letProject);\r\n            return new Bind<A, B, B>(self.CollectedExpressions.Append(letPair), self) {IsLet = true};\r\n        }\r\n\r\n        public static Fetch<C> SelectMany<A, B, C>(this Fetch<A> self, Expression<Func<A, Fetch<B>>> bind, Expression<Func<A, B, C>> project)\r\n        {\r\n            var bindExpression = new BindProjectPair(bind, project);\r\n            var newBinds = self.CollectedExpressions.Append(bindExpression);\r\n            return new Bind<A, B, C>(newBinds, self);\r\n        }\r\n\r\n        public static Fetch<IEnumerable<B>> SelectFetch<A, B>(this IEnumerable<A> list, Func<A, Fetch<B>> bind)\r\n        {\r\n            return new RequestSequence<A, B>(list, bind);\r\n        }\r\n\r\n        public static async Task<A> FetchWith<A>(this Fetch<A> fetch, Fetcher fetcher, HaxlCache cache, Action<HaxlLogEntry> logger)\r\n        {\r\n            var run = fetch.ToHaxlFetch(HAXL_RESULT_NAME, Scope.New());\r\n            var scope = await RunFetch.Run(run, Scope.New(), fetcher.FetchBatch, cache, logger);\r\n            var result = (A)scope.GetValue(HAXL_RESULT_NAME);\r\n            logger(Info(\"==== Result ====\"));\r\n            logger(Info($\"{result}\"));\r\n            return result;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Fetcher.cs",
    "content": "﻿using System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp\r\n{\r\n    /// <summary>\r\n    /// Fetches a request.\r\n    /// </summary>\r\n    public interface Fetcher\r\n    {\r\n        Task FetchBatch(IEnumerable<BlockedRequest> requests);\r\n\r\n        Task<A> Fetch<A>(Fetch<A> request);\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/HaxlLogEntry.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp\r\n{\r\n    public interface HaxlLogEntry\r\n    {\r\n        X Match<X>(Func<InformationLogEntry, X> info, Func<WarningLogEntry, X> warn, Func<ErrorLogEntry, X> error);\r\n        string ToDefaultString();\r\n   }\r\n\r\n    public abstract class BaseLogEntry : HaxlLogEntry\r\n    {\r\n        public readonly DateTime Timestamp;\r\n        public abstract string Message { get; }\r\n        public abstract string Type { get; }\r\n\r\n        public BaseLogEntry()\r\n        {\r\n            Timestamp = DateTime.Now;\r\n        }\r\n\r\n        public abstract X Match<X>(Func<InformationLogEntry, X> info, Func<WarningLogEntry, X> warn, Func<ErrorLogEntry, X> error);\r\n\r\n        public string ToDefaultString()\r\n        {\r\n            return $\"[{Timestamp}] {Type.PadLeft(5)}: {Message}\";\r\n        }\r\n    }\r\n\r\n    public class InformationLogEntry : BaseLogEntry\r\n    {\r\n        public override string Message { get; }\r\n        public override string Type => \"INFO\";\r\n\r\n        public InformationLogEntry(string info)\r\n        {\r\n            Message = info;\r\n        }\r\n\r\n        public override X Match<X>(Func<InformationLogEntry, X> info, Func<WarningLogEntry, X> warn, Func<ErrorLogEntry, X> error)\r\n        {\r\n            return info(this);\r\n        }\r\n    }\r\n\r\n    public class WarningLogEntry : BaseLogEntry\r\n    {\r\n        public override string Message { get; }\r\n        public override string Type => \"WARN\";\r\n        public WarningLogEntry(string warning)\r\n        {\r\n            Message = warning;\r\n        }\r\n\r\n        public override X Match<X>(Func<InformationLogEntry, X> info, Func<WarningLogEntry, X> warn, Func<ErrorLogEntry, X> error)\r\n        {\r\n            return warn(this);\r\n        }\r\n    }\r\n\r\n    public class ErrorLogEntry : BaseLogEntry\r\n    {\r\n        public override string Message { get; }\r\n        public override string Type => \"ERROR\";\r\n        public ErrorLogEntry(string error)\r\n        {\r\n            Message = error;\r\n        }\r\n\r\n        public override X Match<X>(Func<InformationLogEntry, X> info, Func<WarningLogEntry, X> warn, Func<ErrorLogEntry, X> error)\r\n        {\r\n            return error(this);\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/HaxlSharp.Core.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\r\n  <PropertyGroup>\r\n    <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProjectGuid>{56487EB5-C699-4EAA-B384-C6F9E64635C5}</ProjectGuid>\r\n    <OutputType>Library</OutputType>\r\n    <AppDesignerFolder>Properties</AppDesignerFolder>\r\n    <RootNamespace>HaxlSharp</RootNamespace>\r\n    <AssemblyName>HaxlSharp.Core</AssemblyName>\r\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r\n    <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>\r\n    <FileAlignment>512</FileAlignment>\r\n    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <DebugType>full</DebugType>\r\n    <Optimize>false</Optimize>\r\n    <OutputPath>bin\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\r\n    <DebugType>pdbonly</DebugType>\r\n    <Optimize>true</Optimize>\r\n    <OutputPath>bin\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <!-- A reference to the entire .NET Framework is automatically included -->\r\n    <None Include=\"HaxlSharp.Core.nuspec\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"BlockedRequest.cs\" />\r\n    <Compile Include=\"CacheKeyGenerator.cs\" />\r\n    <Compile Include=\"Fetch.cs\" />\r\n    <Compile Include=\"Fetcher.cs\" />\r\n    <Compile Include=\"HaxlLogEntry.cs\" />\r\n    <Compile Include=\"Internal\\Applicative\\HaxlApplicative.cs\" />\r\n    <Compile Include=\"Internal\\Applicative\\SplitApplicative.cs\" />\r\n    <Compile Include=\"Internal\\Base\\Base.cs\" />\r\n    <Compile Include=\"Internal\\Base\\ByteString.cs\" />\r\n    <Compile Include=\"Internal\\Base\\Func.cs\" />\r\n    <Compile Include=\"Internal\\Base\\HaxlConstants.cs\" />\r\n    <Compile Include=\"Internal\\Expressions\\LetExpression.cs\" />\r\n    <Compile Include=\"Internal\\Expressions\\ParameterAccessVisitor.cs\" />\r\n    <Compile Include=\"Internal\\Expressions\\ParseExpression.cs\" />\r\n    <Compile Include=\"Internal\\Expressions\\RebindToScope.cs\" />\r\n    <Compile Include=\"Internal\\Haxl.cs\" />\r\n    <Compile Include=\"Internal\\HaxlCache.cs\" />\r\n    <Compile Include=\"Internal\\Result.cs\" />\r\n    <Compile Include=\"Internal\\RunFetch.cs\" />\r\n    <Compile Include=\"Internal\\Scope.cs\" />\r\n    <Compile Include=\"Internal\\Types\\ApplicativeGroup.cs\" />\r\n    <Compile Include=\"Internal\\Types\\BindProjectPair.cs\" />\r\n    <Compile Include=\"Internal\\Types\\BoundExpression.cs\" />\r\n    <Compile Include=\"Internal\\Types\\CacheResult.cs\" />\r\n    <Compile Include=\"Internal\\Types\\ExpressionVariables.cs\" />\r\n    <Compile Include=\"Internal\\Types\\FreeVariable.cs\" />\r\n    <Compile Include=\"Internal\\Types\\QueryStatement.cs\" />\r\n    <Compile Include=\"Internal\\Types\\ShowList.cs\" />\r\n    <Compile Include=\"Internal\\Types\\Statement.cs\" />\r\n    <Compile Include=\"Internal\\Types\\Unit.cs\" />\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\r\n    <Compile Include=\"Response.cs\" />\r\n    <Compile Include=\"Returns.cs\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildExtensionsPath32)\\Microsoft\\Portable\\$(TargetFrameworkVersion)\\Microsoft.Portable.CSharp.targets\" />\r\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r\n       Other similar extension points exist, see Microsoft.Common.targets.\r\n  <Target Name=\"BeforeBuild\">\r\n  </Target>\r\n  <Target Name=\"AfterBuild\">\r\n  </Target>\r\n  -->\r\n</Project>"
  },
  {
    "path": "HaxlSharp.Core/HaxlSharp.Core.nuspec",
    "content": "<?xml version=\"1.0\"?>\r\n<package >\r\n  <metadata>\r\n    <id>$id$</id>\r\n    <version>$version$</version>\r\n    <title>$title$</title>\r\n    <authors>joashc</authors>\r\n    <projectUrl>https://github.com/joashc/HaxlSharp</projectUrl>\r\n    <requireLicenseAcceptance>false</requireLicenseAcceptance>\r\n    <description>Composable data fetching with automatic concurrency and request deduplication. Contains only the core HaxlSharp functionality. If you don't intend to implement your own fetcher, install the \"HaxlSharp\" package instead.</description>\r\n    <releaseNotes>Initial release.</releaseNotes>\r\n    <copyright>Copyright © 2016 Joash Chong</copyright>\r\n  </metadata>\r\n</package>"
  },
  {
    "path": "HaxlSharp.Core/Internal/Applicative/HaxlApplicative.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing static HaxlSharp.Internal.Base;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    public static class HaxlApplicative\r\n    {\r\n        /// <summary>\r\n        /// Converts a project expression to Haxl monad.\r\n        /// </summary>\r\n        public static Func<Scope, Haxl> ProjectToHaxl(ProjectStatement project, string parentBind)\r\n        {\r\n            return scope => Haxl.FromFunc((cache, logger) =>\r\n            {\r\n                var rewritten = RebindToScope.Rebind(project.Expression);\r\n                var result = rewritten.Compile().DynamicInvoke(scope);\r\n                return Done.New(_ =>\r\n                {\r\n                    if (project.Expression.BindVariable == HAXL_RESULT_NAME\r\n                        && !scope.IsRoot\r\n                        && parentBind != null)\r\n                    {\r\n                        return scope.WriteParent(parentBind, result);\r\n                    }\r\n                    return scope.Add(project.Expression.BindVariable, result);\r\n                });\r\n            });\r\n        }\r\n\r\n        /// <summary>\r\n        /// Converts a single bind expression to the Haxl monad.\r\n        /// </summary>\r\n        /// <param name=\"bind\"></param>\r\n        /// <returns></returns>\r\n        public static Func<Scope, Haxl> BindToHaxl(BindStatement bind)\r\n        {\r\n            return scope =>\r\n            {\r\n                var rewritten = RebindToScope.Rebind(bind.Expression);\r\n                var value = rewritten.Compile().DynamicInvoke(scope);\r\n                var wrapped = (Fetchable)value;\r\n                return wrapped.ToHaxlFetch(bind.Expression.BindVariable, scope);\r\n            };\r\n        }\r\n\r\n        /// <summary>\r\n        /// Converts to Haxl monad, dispatching on statement type.\r\n        /// </summary>\r\n        public static Func<Scope, Haxl> StatementToHaxl(Statement statement, string parentBind)\r\n        {\r\n            return statement.Match(\r\n                BindToHaxl,\r\n                project => ProjectToHaxl(project, parentBind));\r\n        }\r\n\r\n        /// <summary>\r\n        /// Folds an applicative group into a Haxl monad.\r\n        /// </summary>\r\n        public static Func<Scope, Haxl> ApplicativeToHaxl(ApplicativeGroup applicative, string parentBind)\r\n        {\r\n            var expressions = applicative.Expressions;\r\n            if (applicative.Expressions.Count == 1) return StatementToHaxl(expressions.First(), parentBind);\r\n            return scope => applicative.Expressions.Aggregate\r\n                (\r\n                    Haxl.FromFunc((c, l) => Done.New(s => s)),\r\n                    (group, be) =>\r\n                    {\r\n                        var haxl = StatementToHaxl(be, parentBind)(scope);\r\n                        return group.Applicative(haxl);\r\n                    }\r\n                );\r\n        }\r\n\r\n        /// <summary>\r\n        /// Converts a list of applicative groups into a Haxl monad.\r\n        /// </summary>\r\n        public static Haxl ToFetch(List<ApplicativeGroup> split, string parentBind, Scope parentScope)\r\n        {\r\n            if (parentScope == null) parentScope = Scope.New();\r\n            Haxl finalFetch = null;\r\n            Action<Func<Scope, Haxl>> bindToFinal = f =>\r\n            {\r\n                finalFetch = finalFetch == null ? f(parentScope) : finalFetch.Bind(f);\r\n            };\r\n\r\n            foreach (var applicative in split)\r\n            {\r\n                bindToFinal(ApplicativeToHaxl(applicative, parentBind));\r\n            }\r\n            return finalFetch;\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Applicative/SplitApplicative.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Linq.Expressions;\r\nusing static HaxlSharp.Internal.Base;\r\nusing System.Text.RegularExpressions;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    public class SplitApplicative\r\n    {\r\n        /// <summary>\r\n        /// Splits a monadic bind into applicative groups. \r\n        /// </summary>\r\n        public static List<ApplicativeGroup> SplitBind(IEnumerable<BindProjectPair> collectedExpressions,\r\n            LambdaExpression initial)\r\n        {\r\n            var vars = collectedExpressions.Select(GetVariables).ToList();\r\n            var numbered = NumberBlocks(vars).ToList();\r\n            return MakeApplicative(initial, numbered);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Gets the variables in a (bind, project) pair.\r\n        /// </summary>\r\n        private static QueryStatement GetVariables(BindProjectPair pair)\r\n        {\r\n            var project = pair.Project;\r\n            var isLet = project.Parameters.Any(param => param.Name.StartsWith(LET_PREFIX));\r\n            if (isLet)\r\n            {\r\n                var letParam = project.Parameters.ElementAt(1);\r\n                var letName = letParam.Name;\r\n                var originalName = Regex.Split(letName, LET_PREFIX)[1];\r\n                var letExpression = Expression.Lambda(project.Body, project.Parameters.First(),\r\n                    Expression.Parameter(letParam.Type, originalName));\r\n                var letVariables = ParseExpression.GetExpressionVariables(letExpression);\r\n                return new LetStatement(originalName, letExpression, letVariables);\r\n            }\r\n            var bindVars = ParseExpression.GetExpressionVariables(pair.Bind);\r\n            var projectVars = ParseExpression.GetExpressionVariables(project);\r\n            return new BindProjectStatement(pair, bindVars, projectVars) { IsSelect = pair.IsSelect };\r\n        }\r\n\r\n\r\n        /// <summary>\r\n        /// Appends numbers indicating the block a statement belongs to.\r\n        /// <remarks>\r\n        /// A statement written in the format:\r\n        /// \r\n        /// > var nested = from x in a\r\n        /// >              from y in b\r\n        /// >              select x + y;\r\n        /// >\r\n        /// > var fetch = from x in nested\r\n        /// >             from y in b\r\n        /// >             select x + y;\r\n        /// \r\n        /// will be rewritten as:\r\n        /// \r\n        /// > a.SelectMany(\r\n        /// >   x => b,\r\n        /// >   x, y => x + y\r\n        /// > ).SelectMany(\r\n        /// >   x => b\r\n        /// >   x, y =>  x + y\r\n        /// > );\r\n        /// \r\n        /// Because there are two variables named \"x\", and these \r\n        /// expressions are written inline, we need to number them,\r\n        /// in case they end up in the same applicative group.\r\n        /// </remarks>\r\n        /// </summary>\r\n        public static IEnumerable<QueryStatement> NumberBlocks(List<QueryStatement> statements)\r\n        {\r\n            var blockNumber = 0;\r\n            var statementCounter = 0;\r\n            var numStatements = statements.Count();\r\n            var isFirst = true;\r\n            foreach (var statement in statements)\r\n            {\r\n                statementCounter++;\r\n                // SplitBind functions that take one non-transparent parameter are binding the entire result from another monad.\r\n                // This will hide any variables that were in scope in that monad.\r\n                statement.StartsBlock = isFirst;\r\n                if (statement.Match(\r\n                    bind => bind.BindVariables.ParameterNames.Count == 1\r\n                            && !ParseExpression.IsTransparent(bind.Expressions.Bind.Parameters.First()),\r\n                    let => false)\r\n                    )\r\n                {\r\n                    blockNumber++;\r\n                    statement.StartsBlock = true;\r\n                }\r\n                statement.BlockNumber = blockNumber;\r\n                if (statementCounter == numStatements) statement.IsFinal = true;\r\n                isFirst = false;\r\n                yield return statement;\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Groups statements that can be fetched concurrently.\r\n        /// </summary>\r\n        public static List<ApplicativeGroup> MakeApplicative(LambdaExpression initial,\r\n            IEnumerable<QueryStatement> statements)\r\n        {\r\n            var applicatives = new List<ApplicativeGroup>();\r\n            LambdaExpression previousProject = initial;\r\n            ExpressionVariables previousProjectVars = null;\r\n            var currentApplicative = new List<Statement>();\r\n            var boundInGroup = new List<string>();\r\n\r\n            Action split = () =>\r\n            {\r\n                if (currentApplicative.Any()) applicatives.Add(new ApplicativeGroup(currentApplicative));\r\n                currentApplicative = new List<Statement>();\r\n                boundInGroup.Clear();\r\n            };\r\n\r\n            var first = true;\r\n\r\n            foreach (var statement in statements)\r\n            {\r\n                var blockNumber = statement.BlockNumber;\r\n                Func<LambdaExpression, string, BoundExpression>\r\n                boundExpression = (e, s) => new BoundExpression(e, s, blockNumber);\r\n\r\n                statement.Match(\r\n                    bind =>\r\n                    {\r\n                        // The result of the previous monad is bound to this variable name.\r\n                        var previousBindName = bind.BindVariables.ParameterNames.First();\r\n                        var prefixed = PrefixedVariable(blockNumber, previousBindName);\r\n\r\n                        if (first) // Add the initial fetch. \r\n                        {\r\n                            currentApplicative.Add(new BindStatement(boundExpression(initial, prefixed)));\r\n                        }\r\n\r\n                        var shouldSplit = ShouldSplit(bind.BindVariables, boundInGroup);\r\n                        if (shouldSplit) split();\r\n\r\n                        // If we're at the beginning of a new block, we should add the previous project statement.\r\n                        if (bind.StartsBlock && !first)\r\n                        {\r\n                            var splitBlock = previousProjectVars != null && ShouldSplit(previousProjectVars, boundInGroup);\r\n                            if (splitBlock) split();\r\n                            boundInGroup.Clear();\r\n                            currentApplicative.Add(\r\n                                // This project was from the previous block, so we subtract one here.\r\n                                new ProjectStatement(new BoundExpression(previousProject, prefixed, blockNumber - 1)));\r\n                            if (shouldSplit) split();\r\n                        }\r\n\r\n                        // The result of the current monad is bound to the second parameter of the project fuction:\r\n                        // x.SelectMany(\r\n                        //     a => m a,\r\n                        //     a, b => new { a, b }  \r\n                        //                   // ^ this b is the result of m a.\r\n                        // )\r\n                        var bindName = bind.ProjectVariables.ParameterNames.Last();\r\n                        var prefixedBindName = PrefixedVariable(blockNumber, bindName);\r\n                        currentApplicative.Add(new BindStatement(boundExpression(bind.Expressions.Bind, prefixedBindName)));\r\n\r\n                        // We take the final projection function and bind it to the HAXL_RESULT_NAME constant.\r\n                        if (bind.IsFinal)\r\n                        {\r\n                            split();\r\n                            currentApplicative.Add(new ProjectStatement(boundExpression(bind.Expressions.Project, HAXL_RESULT_NAME)));\r\n                        }\r\n\r\n                        // Push out the project function and its variables in case it's the final select of \r\n                        // a nested block and we need to bind it.\r\n                        previousProject = bind.Expressions.Project;\r\n                        previousProjectVars = bind.ProjectVariables;\r\n\r\n                        // If we've split the only dependency is the current monad.\r\n                        if (shouldSplit) boundInGroup.Add(bindName);\r\n                        else boundInGroup.AddRange(bind.ProjectVariables.ParameterNames);\r\n                        return UnitVal;\r\n                    },\r\n                    let =>\r\n                    {\r\n                        var paramNames = let.Variables.ParameterNames;\r\n                        var previousBindName = paramNames.First();\r\n                        var prefixed = PrefixedVariable(blockNumber, previousBindName);\r\n                        if (ShouldSplit(previousProjectVars, boundInGroup)) split();\r\n\r\n                        // The initial lambda is always returns a monad, so we place it into a bind.\r\n                        if (first) currentApplicative.Add(new BindStatement(boundExpression(previousProject, prefixed)));\r\n                        else if (!LetExpression.IsLetExpression(previousProject)) currentApplicative.Add(new ProjectStatement(boundExpression(previousProject, prefixed)));\r\n\r\n                        boundInGroup.Add(let.Variables.ParameterNames.First());\r\n\r\n                        if (ShouldSplit(let.Variables, boundInGroup)) split();\r\n\r\n                        boundInGroup.Add(let.Name);\r\n                        currentApplicative.Add(new ProjectStatement(boundExpression(let.Expression, PrefixedVariable(blockNumber, let.Name))));\r\n                        return UnitVal;\r\n                    }\r\n                    );\r\n                first = false;\r\n            }\r\n            if (currentApplicative.Any()) applicatives.Add(new ApplicativeGroup(currentApplicative));\r\n            return applicatives;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Checks if this expression binds any variables bound in the current group.\r\n        /// </summary>\r\n        private static bool ShouldSplit(ExpressionVariables vars, List<string> boundInGroup)\r\n        {\r\n            if (vars == null) return false;\r\n            if (vars.BindsNonTransparentParam) return true;\r\n            if (vars.Bound.Any(boundInGroup.Contains)) return true;\r\n            return false;\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Base/Base.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// Contains constructor functions.\r\n    /// </summary>\r\n    public static partial class Base\r\n    {\r\n        public static IEnumerable<A> Append<A>(this IEnumerable<A> list, A value)\r\n        {\r\n            var appendList = new List<A>(list);\r\n            appendList.Add(value);\r\n            return appendList;\r\n        }\r\n\r\n        public static ShowList<A> ShowList<A>(IEnumerable<A> list)\r\n        {\r\n            return new ShowList<A>(list);\r\n        }\r\n\r\n        public static InformationLogEntry Info(string info)\r\n        {\r\n            return new InformationLogEntry(info);\r\n        }\r\n\r\n        public static WarningLogEntry Warn(string warn)\r\n        {\r\n            return new WarningLogEntry(warn);\r\n        }\r\n\r\n        public static ErrorLogEntry Error(string error)\r\n        {\r\n            return new ErrorLogEntry(error);\r\n        }\r\n\r\n        public static Unit UnitVal = new Unit();\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Base/ByteString.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    public static partial class Base\r\n    {\r\n        public static readonly Func<string, byte[]> StringBytes = new UTF8Encoding().GetBytes;\r\n\r\n        public static readonly Func<byte[], string> ToLowerHexString = bs => bs.Aggregate(new StringBuilder(32), (sb, b) => sb.Append(b.ToString(\"x2\"))).ToString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Base/Func.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    public static partial class Base\r\n    {\r\n        public static Func<A> func<A>(Func<A> func) { return func; }\r\n        public static Func<A,B> func<A,B>(Func<A,B> func) { return func; }\r\n        public static Func<A,B,C> func<A,B,C>(Func<A,B,C> func) { return func; }\r\n        public static Func<A,B,C,D> func<A,B,C,D>(Func<A,B,C,D> func) { return func; }\r\n\r\n        public static Func<A, C> compose<A, B, C>(Func<B, C> f2, Func<A, B> f1) { return x => f2(f1(x)); }\r\n        public static Func<A, D> compose<A, B, C, D>(Func<C, D> f3, Func<B, C> f2, Func<A, B> f1) { return x => f3(f2(f1(x))); }\r\n        public static Func<A, E> compose<A, B, C, D, E>(Func<D, E> f4, Func<C, D> f3, Func<B, C> f2, Func<A, B> f1) { return x => f4(f3(f2(f1(x)))); }\r\n        public static Func<A, F> compose<A, B, C, D, E, F>(Func<E, F> f5, Func<D, E> f4, Func<C, D> f3, Func<B, C> f2, Func<A, B> f1) { return x => f5(f4(f3(f2(f1(x))))); }\r\n\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Base/HaxlConstants.cs",
    "content": "﻿\r\nusing System;\r\nusing System.Text.RegularExpressions;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    public static partial class Base\r\n    {\r\n        /// <summary>\r\n        /// We prefix with \"<>\" so we can't clash with actual bound variable names. \r\n        /// </summary>\r\n        public const string HAXL_RESULT_NAME = \"<>HAXL_RESULT\";\r\n\r\n        /// <summary>\r\n        /// All transparent identifiers start with this prefix.\r\n        /// </summary>\r\n        public const string TRANSPARENT_PREFIX = \"<>h__Trans\";\r\n\r\n        /// <summary>\r\n        /// We mark let expressions with this prefix.\r\n        /// </summary>\r\n        public const string LET_PREFIX = \"<>HAXL_LET\";\r\n\r\n        /// <summary>\r\n        /// Annotate let arguments with the let prefix.\r\n        /// </summary>\r\n        public static string PrefixLet(string letVarName)\r\n        {\r\n            return $\"{LET_PREFIX}{letVarName}\";\r\n        }\r\n\r\n        /// <summary>\r\n        /// Combines variable names with block numbers.\r\n        /// </summary>\r\n        public static string PrefixedVariable(int blockNumber, string variableName)\r\n        {\r\n            return $\"({blockNumber}) {variableName}\";\r\n        }\r\n\r\n        public static int GetBlockNumber(string bindTo)\r\n        {\r\n            if (bindTo == HAXL_RESULT_NAME) return 0;\r\n            var regex = @\"^\\((\\d+)\\).*$\";\r\n            var match = Regex.Match(bindTo, regex);\r\n            if (match.Groups.Count < 2)  throw new ArgumentException(\"Invalid bind variable name\");\r\n            return int.Parse(match.Groups[1].Value);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Expressions/LetExpression.cs",
    "content": "﻿using System;\r\nusing System.Linq;\r\nusing System.Linq.Expressions;\r\nusing static HaxlSharp.Internal.Base;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    public static class LetExpression\r\n    {\r\n        /// <summary>\r\n        /// Checks if a select expression is a Let.\r\n        /// </summary>\r\n        /// <remarks>\r\n        /// This is not a reliable test; it only checks if:\r\n        /// - The lambda body is just a new expression\r\n        /// - It returns an anonymous type\r\n        /// - The parameter name is the same as the first member\r\n        /// \r\n        /// If we were to write a select with all these attributes:\r\n        /// \r\n        /// </remarks>\r\n        public static bool IsLetExpression(LambdaExpression expression)\r\n        {\r\n            if (expression.Body.NodeType != ExpressionType.New) return false;\r\n            var newExpression = (NewExpression)expression.Body;\r\n            if (newExpression.Arguments.Count != 2) return false;\r\n            if (!expression.ReturnType.Name.StartsWith(\"<>f__AnonymousType\")) return false;\r\n            var paramName = expression.Parameters.First().Name;\r\n            if (paramName != newExpression.Members.First().Name) return false;\r\n            return true;\r\n        }\r\n\r\n        public static LambdaExpression RewriteLetExpression<A, B>(Expression<Func<A, B>> expression)\r\n        {\r\n            var body = (NewExpression)expression.Body;\r\n            var letVar = body.Arguments.ElementAt(1);\r\n            var letParam = body.Members.ElementAt(1);\r\n            return Expression.Lambda(letVar, expression.Parameters.First(), Expression.Parameter(letVar.Type, PrefixLet(letParam.Name)));\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Expressions/ParameterAccessVisitor.cs",
    "content": "﻿using System.Collections.Generic;\r\nusing System.Linq.Expressions;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// Recursively collects the parameter and member accesses of a given expression.\r\n    /// </summary>\r\n    public class ParameterAccessVisitor : ExpressionVisitor\r\n    {\r\n        public readonly List<ParameterExpression> ParameterAccesses;\r\n        public readonly List<MemberExpression> MemberAccesses;\r\n        public ParameterAccessVisitor()\r\n        {\r\n            ParameterAccesses = new List<ParameterExpression>();\r\n            MemberAccesses = new List<MemberExpression>();\r\n        }\r\n\r\n        protected override Expression VisitParameter(ParameterExpression node)\r\n        {\r\n            ParameterAccesses.Add(node);\r\n            return base.VisitParameter(node);\r\n        }\r\n\r\n        protected override Expression VisitMember(MemberExpression node)\r\n        {\r\n            MemberAccesses.Add(node);\r\n            return base.VisitMember(node);\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Expressions/ParseExpression.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Linq.Expressions;\r\nusing System.Reflection;\r\nusing static HaxlSharp.Internal.Base;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    public static class ParseExpression\r\n    {\r\n        /// <summary>\r\n        /// Gets the free and bound variables of a lambda expression.\r\n        /// </summary>\r\n        public static ExpressionVariables GetExpressionVariables(LambdaExpression bind)\r\n        {\r\n            var visitor = new ParameterAccessVisitor();\r\n            visitor.Visit(bind.Body);\r\n            var bound = visitor.MemberAccesses\r\n                               .Select(MemberAccess)\r\n                               .Where(m => !m.Name.StartsWith(TRANSPARENT_PREFIX) && m.FromTransparent)\r\n                               .Select(f => f.Name)\r\n                               .ToList();\r\n\r\n            var paramVisitor = new ParameterAccessVisitor();\r\n            foreach (var param in bind.Parameters)\r\n            {\r\n                paramVisitor.Visit(param);\r\n            }\r\n            var bindsNonTransparent = bind.Parameters.Any(\r\n                bindParam =>\r\n                    !IsTransparent(bindParam) && BindsNonTransparentParam(visitor.ParameterAccesses, bindParam.Name));\r\n            return new ExpressionVariables(bindsNonTransparent, bound, paramVisitor.ParameterAccesses.SelectMany(MemberNames).Select(f => f.Name).ToList());\r\n        }\r\n\r\n        /// <summary>\r\n        /// Get all member names within a parameter expression.\r\n        /// </summary>\r\n        private static IEnumerable<FreeVariable> MemberNames(ParameterExpression parameter)\r\n        {\r\n            // Transparent identifiers start with this prefix\r\n            // If we have a transparent identifier, we pull out the appropriate members.\r\n            if (parameter.Name.StartsWith(TRANSPARENT_PREFIX))\r\n            {\r\n                var properties = parameter.Type.GetRuntimeProperties();\r\n                return from property in properties\r\n                       where !property.Name.StartsWith(TRANSPARENT_PREFIX)\r\n                       select new FreeVariable(property.Name, true);\r\n            }\r\n            return new List<FreeVariable> { new FreeVariable(parameter.Name, false) };\r\n        }\r\n\r\n        private static bool BindsNonTransparentParam(List<ParameterExpression> parameterExpressions, string paramName)\r\n        {\r\n            return parameterExpressions.Any(pe => pe.Name == paramName);\r\n        }\r\n\r\n\r\n        /// <summary>\r\n        /// Checks if a given member expression ultimately points to a transparent identifier.\r\n        /// </summary>\r\n        public static bool IsFromTransparent(MemberExpression expression)\r\n        {\r\n            if (expression.Expression == null) return false;\r\n            switch (expression.Expression.NodeType)\r\n            {\r\n                case ExpressionType.Parameter:\r\n                    return IsTransparent((ParameterExpression)expression.Expression);\r\n                case ExpressionType.Constant:\r\n                    return false;\r\n            }\r\n            return IsFromTransparent(expression.Expression as MemberExpression);\r\n        }\r\n\r\n\r\n        public static bool IsTransparent(ParameterExpression expression)\r\n        {\r\n            return expression.Name.StartsWith(TRANSPARENT_PREFIX);\r\n        }\r\n\r\n        /// <summary>\r\n        /// \r\n        /// </summary>\r\n        public static bool IsTransparentMember(MemberExpression expression)\r\n        {\r\n            return expression.Member.Name.StartsWith(TRANSPARENT_PREFIX);\r\n        }\r\n\r\n        /// <summary>\r\n        /// \r\n        /// </summary>\r\n        private static FreeVariable MemberAccess(MemberExpression argument)\r\n        {\r\n            //return new FreeVariable(argument.Member.Name, false);\r\n            var fromTransparent = IsFromTransparent(argument);\r\n            if (!fromTransparent) return new FreeVariable(argument.Member.Name, false);\r\n            switch (argument.Expression.NodeType)\r\n            {\r\n                case ExpressionType.Parameter:\r\n                    return new FreeVariable(argument.Member.Name, true);\r\n                case ExpressionType.MemberAccess:\r\n                {\r\n\r\n                    var member = (MemberExpression) argument.Expression;\r\n                    return member.Member.Name.StartsWith(TRANSPARENT_PREFIX) \r\n                            ? new FreeVariable(argument.Member.Name, true) \r\n                            : MemberAccess(member);\r\n                }\r\n            }\r\n            throw new ArgumentException(\"Error getting transparent identifier name\");\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Expressions/RebindToScope.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Linq.Expressions;\r\nusing System.Reflection;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\nusing static HaxlSharp.Internal.Base;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// Replaces all transparent identifier or parameter accessor expressions with expressions that read from scope parameter.\r\n    /// </summary>\r\n    public class RebindToScope : ExpressionVisitor\r\n    {\r\n        private List<string> paramNames;\r\n        private ParameterExpression scopeParam;\r\n        public int BlockCount { get; set; }\r\n        private MethodInfo GetValue = typeof(Scope).GetRuntimeMethod(\"GetValue\", new Type[] { typeof(string) });\r\n\r\n        /// <summary>\r\n        /// Replace all parameters with a single scope parameter, then rewrite body to read from that scope.\r\n        /// </summary>\r\n        public LambdaExpression Rebind(LambdaExpression lambda)\r\n        {\r\n            paramNames = lambda.Parameters.Select(p => p.Name).Where(n => !n.StartsWith(TRANSPARENT_PREFIX)).ToList();\r\n            scopeParam = Expression.Parameter(typeof(Scope), \"scope\");\r\n            var newExpression =\r\n                Expression.Lambda(\r\n                    lambda.Body,\r\n                    new ParameterExpression[]\r\n                    {\r\n                        scopeParam\r\n                    }\r\n               );\r\n            return (LambdaExpression)base.Visit(newExpression);\r\n        }\r\n\r\n        public static LambdaExpression Rebind(BoundExpression expression)\r\n        {\r\n            var rebinder = new RebindToScope {BlockCount = expression.BlockNumber};\r\n            return rebinder.Rebind(expression.Expression);\r\n        }\r\n\r\n        /// <summary>\r\n        /// We only want to rewrite transparent identifier accessors.\r\n        /// </summary>\r\n        protected override Expression VisitMember(MemberExpression node)\r\n        {\r\n            if (ParseExpression.IsFromTransparent(node) && !ParseExpression.IsTransparentMember(node))\r\n            {\r\n                return RewritePropertyAccess(node);\r\n            }\r\n            return base.VisitMember(node);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Rewrites transparent identifier accessors.\r\n        /// </summary>\r\n        /// <remarks>\r\n        /// If we have a nested accessor, like:\r\n        /// > ti0.ti1.a.b.c\r\n        /// this will rewrite the expression as:\r\n        /// > SCOPE.a.b.c\r\n        /// </remarks>\r\n        private Expression RewritePropertyAccess(MemberExpression node)\r\n        {\r\n            Expression current = node;\r\n            var expressionStack = new Stack<Expression>();\r\n            while (current.NodeType == ExpressionType.MemberAccess)\r\n            {\r\n                var memberAccess = ((MemberExpression)current);\r\n                if (!memberAccess.Member.Name.StartsWith(TRANSPARENT_PREFIX)) expressionStack.Push(current);\r\n                current = memberAccess.Expression;\r\n            }\r\n\r\n            var property = (MemberExpression)expressionStack.Pop();\r\n            var propertyName = property.Member.Name;\r\n\r\n            var value = Expression.Call(scopeParam, GetValue, Expression.Constant(PrefixedVariable(BlockCount, propertyName))); \r\n            Expression rewritten = Expression.Convert(value, property.Type);\r\n\r\n            while (expressionStack.Any())\r\n            {\r\n                var top = expressionStack.Pop();\r\n                rewritten = Expression.MakeMemberAccess(rewritten, ((MemberExpression)top).Member);\r\n            }\r\n            return rewritten;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Rewrites parameter accessors to read from scope.\r\n        /// </summary>\r\n        protected override Expression VisitParameter(ParameterExpression node)\r\n        {\r\n            if (paramNames.Contains(node.Name))\r\n            {\r\n                var memberType = node.Type;\r\n                var memberName = node.Name;\r\n                var value = Expression.Call(scopeParam, GetValue, Expression.Constant(PrefixedVariable(BlockCount, memberName)));\r\n                return Expression.Convert(value, memberType);\r\n            }\r\n            return node;\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Haxl.cs",
    "content": "﻿using System;\r\nusing System.Linq;\r\nusing static HaxlSharp.Internal.Base;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// The Haxl monad.\r\n    /// </summary>\r\n    public class Haxl\r\n    {\r\n        /// <summary>\r\n        /// The result of the fetch.\r\n        /// </summary>\r\n        /// <remarks>\r\n        /// Accessing a Done result before it's fetched is a framework error.\r\n        /// </remarks>\r\n        public readonly Func<HaxlCache, Action<HaxlLogEntry>, Result> Result;\r\n\r\n        public Haxl(Func<HaxlCache, Action<HaxlLogEntry>, Result> result)\r\n        {\r\n            Result = result;\r\n        }\r\n\r\n        public static Haxl FromFunc(Func<HaxlCache, Action<HaxlLogEntry>, Result> resultFunc)\r\n        {\r\n            return new Haxl(resultFunc);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Applicative pure.\r\n        /// <remarks>\r\n        /// We need a bind variable string because our applicative instance is specialized to (Scope -> Scope) functions.\r\n        /// </remarks>\r\n        /// </summary>\r\n        public static Haxl Pure(string bindTo, object value)\r\n        {\r\n            return FromFunc((cache, logger) => Done.New(scope => scope.Add(bindTo, value)));\r\n        }\r\n\r\n        /// <summary>\r\n        /// Identity >>= (scope -> x) = x = x >>= (scope -> Identity)\r\n        /// </summary>\r\n        public static Haxl Identity()\r\n        {\r\n            return FromFunc((cache, logger) => Done.New(s => s));\r\n        }\r\n\r\n        public Haxl Map(Func<Scope, Scope> addResult)\r\n        {\r\n            return new Haxl((cache, logger) =>\r\n            {\r\n                var result = Result(cache, logger);\r\n                return result.Match<Result>(\r\n                    done => Done.New(compose(addResult, done.AddToScope)),\r\n                    blocked => Blocked.New(blocked.BlockedRequests, blocked.Continue.Map(addResult))\r\n                );\r\n            });\r\n        }\r\n    }\r\n\r\n    public static class HaxlFetchExt\r\n    {\r\n        /// <summary>\r\n        /// Monad instance for HaxlFetch.\r\n        /// </summary>\r\n        public static Haxl Bind(this Haxl fetch, Func<Scope, Haxl> bind)\r\n        {\r\n            return Haxl.FromFunc((cache, logger) =>\r\n            {\r\n                var result = fetch.Result(cache, logger);\r\n                return result.Match(\r\n                    done => bind(done.AddToScope(Scope.New())).Result(cache, logger),\r\n                    blocked => Blocked.New(blocked.BlockedRequests, blocked.Continue.Bind(bind))\r\n                );\r\n            });\r\n        }\r\n\r\n        /// <summary>\r\n        /// \"Applicative\" instance for HaxlFetch.\r\n        /// </summary>\r\n        /// <remarks>\r\n        /// This isn't a true applicative instance; we don't have:\r\n        /// \r\n        /// > (<*>) :: f (a -> b) -> f a -> f b\r\n        /// \r\n        /// In Haskell Haxl, the applicative instance is used to keep fetched values in scope:\r\n        /// \r\n        /// > (a, b) <- (,) <$> fetch1 <*> fetch2\r\n        /// \r\n        /// C# can't do nested lambda scoping, and uses transparent identifers instead.\r\n        /// Because the transparent identifers aren't accessible to us, we use our own scoping system.\r\n        /// \r\n        /// This means our (a -> b) function is *always* (Scope -> Scope);\r\n        /// we therefore can write our \"Applicative\" instance as simply a function that takes two Fetches.\r\n        /// </remarks>\r\n        public static Haxl Applicative(this Haxl fetch1, Haxl fetch2)\r\n        {\r\n            return Haxl.FromFunc((cache, logger) =>\r\n            {\r\n                var result1 = fetch1.Result(cache, logger);\r\n                var result2 = fetch2.Result(cache, logger);\r\n                return result1.Match\r\n                (\r\n                    done1 => result2.Match<Result>\r\n                    (\r\n                        done2 => Done.New(compose(done2.AddToScope, done1.AddToScope)),\r\n                        blocked2 => Blocked.New(blocked2.BlockedRequests, blocked2.Continue.Map(done1.AddToScope))\r\n                    ),\r\n\r\n                    blocked1 => result2.Match<Result>\r\n                    (\r\n                        done2 => Blocked.New(blocked1.BlockedRequests, blocked1.Continue.Map(done2.AddToScope)),\r\n                        blocked2 => Blocked.New(\r\n                            blocked1.BlockedRequests.Concat(blocked2.BlockedRequests),\r\n                            blocked1.Continue.Applicative(blocked2.Continue)\r\n                        )\r\n                    )\r\n                );\r\n            });\r\n        }\r\n    }\r\n\r\n\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/HaxlCache.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// Caches results per-request for deduplication.\r\n    /// </summary>\r\n    public class HaxlCache\r\n    {\r\n        private readonly CacheKeyGenerator _keyGenerator;\r\n        private readonly Dictionary<string, BlockedRequest> _cache;\r\n        public HaxlCache(CacheKeyGenerator generator)\r\n        {\r\n            _keyGenerator = generator;\r\n            _cache = new Dictionary<string, BlockedRequest>();\r\n        }\r\n\r\n        public CacheResult Lookup<A>(Returns<A> request)\r\n        {\r\n            var key = _keyGenerator.ForRequest(request);\r\n            if (!_cache.ContainsKey(key)) return CacheResult.NotFound;\r\n            var blockedRequest = _cache[key];\r\n            return CacheResult.Found(blockedRequest);\r\n        }\r\n\r\n        public void Insert<A>(Returns<A> request, BlockedRequest blocked)\r\n        {\r\n            var key = _keyGenerator.ForRequest(request);\r\n            if (_cache.ContainsKey(key)) throw new Exception(\"Internal Haxl error: attempted to cache duplicate request.\");\r\n            _cache[key] = blocked;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Result.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// The result of a fetch.\r\n    /// </summary>\r\n    public interface Result\r\n    {\r\n        X Match<X>(Func<Done, X> done, Func<Blocked, X> blocked);\r\n    }\r\n\r\n    /// <summary>\r\n    /// The result of a completed fetch.\r\n    /// </summary>\r\n    public class Done : Result\r\n    {\r\n        public Func<Scope, Scope> AddToScope;\r\n\r\n        public static Done New(Func<Scope, Scope> addToScope)\r\n        {\r\n            return new Done(addToScope);\r\n        }\r\n\r\n        public Done(Func<Scope, Scope> addToScope)\r\n        {\r\n            AddToScope = addToScope;\r\n        }\r\n\r\n        public X Match<X>(Func<Done, X> done, Func<Blocked, X> blocked)\r\n        {\r\n            return done(this);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// A result that's blocked on one or more requests.  \r\n    /// </summary>\r\n    public class Blocked : Result\r\n    {\r\n        public readonly IEnumerable<BlockedRequest> BlockedRequests;\r\n        public readonly Haxl Continue;\r\n\r\n        public static Blocked New(IEnumerable<BlockedRequest> blocked, Haxl cont)\r\n        {\r\n            return new Blocked(blocked, cont);\r\n        }\r\n\r\n        private Blocked(IEnumerable<BlockedRequest> blocked, Haxl cont)\r\n        {\r\n            BlockedRequests = blocked;\r\n            Continue = cont;\r\n        }\r\n\r\n        public X Match<X>(Func<Done, X> done, Func<Blocked, X> blocked)\r\n        {\r\n            return blocked(this);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/RunFetch.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    public static class RunFetch\r\n    {\r\n        /// <summary>\r\n        /// Repeatedly fetches requests until we have the result.\r\n        /// </summary>\r\n        public static async Task<Scope> Run(Haxl fetch, Scope scope, Func<IEnumerable<BlockedRequest>, Task> fetcher, HaxlCache cache, Action<HaxlLogEntry> logger)\r\n        {\r\n            var result = fetch.Result(cache, logger);\r\n            return await result.Match(\r\n                done => Task.FromResult(done.AddToScope(scope)),\r\n                async blocked =>\r\n                {\r\n                    await fetcher(blocked.BlockedRequests);\r\n                    return await Run(blocked.Continue, scope, fetcher, cache, logger);\r\n                }\r\n            );\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Scope.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing static HaxlSharp.Internal.Base;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// Scope with simple inheritance that \"shadows\" variable names.\r\n    /// </summary>\r\n    public class Scope\r\n    {\r\n        private readonly Dictionary<string, object> boundVariables;\r\n        private readonly Scope parentScope;\r\n\r\n        public static Scope New()\r\n        {\r\n            return new Scope();\r\n        }\r\n\r\n        public Scope()\r\n        {\r\n            boundVariables = new Dictionary<string, object>();\r\n            parentScope = null;\r\n        }\r\n\r\n        public Scope(Scope scope)\r\n        {\r\n            boundVariables = new Dictionary<string, object>();\r\n            parentScope = scope;\r\n        }\r\n\r\n        public bool IsRoot => parentScope == null;\r\n\r\n        public virtual object GetValue(string variableName)\r\n        {\r\n            if (boundVariables.ContainsKey(variableName)) return boundVariables[variableName];\r\n            if (parentScope == null) throw new ArgumentException($\"No variable named '{variableName}' in scope.\");\r\n            return parentScope.GetValue(variableName);\r\n        }\r\n\r\n        public bool InScope(string variableName)\r\n        {\r\n            if (boundVariables.ContainsKey(variableName)) return true;\r\n            if (parentScope == null) return false;\r\n            return parentScope.InScope(variableName);\r\n        }\r\n\r\n        public Scope Add(string name, object value)\r\n        {\r\n            boundVariables[name] = value;\r\n            return this;\r\n        }\r\n\r\n        public int GetLatestBlockNumber()\r\n        {\r\n            if (!Keys.Any()) return 0;\r\n            return Keys.Select(GetBlockNumber).Max();\r\n        }\r\n\r\n        public Scope WriteParent(string name, object value)\r\n        {\r\n            if (parentScope == null) return Add(name, value);\r\n            return parentScope.Add(name, value);\r\n        }\r\n\r\n        public IEnumerable<string> Keys\r\n        {\r\n            get\r\n            {\r\n                if (parentScope == null) return boundVariables.Keys;\r\n                return boundVariables.Keys.Concat(parentScope.Keys);\r\n            }\r\n        }\r\n\r\n        public IEnumerable<object> ShallowValues => boundVariables.Values;\r\n    }\r\n\r\n    /// <summary>\r\n    /// A specialized scope object that will return a fixed value for the first unknown key request.\r\n    /// </summary>\r\n    public class SelectScope : Scope\r\n    {\r\n        private readonly object _selectValue;\r\n        private string _unknownName;\r\n        public SelectScope(object selectValue, Scope scope) : base(scope)\r\n        {\r\n            _selectValue = selectValue;\r\n        }\r\n\r\n        public override object GetValue(string variableName)\r\n        {\r\n            try\r\n            {\r\n                return base.GetValue(variableName);\r\n            }\r\n            catch (ArgumentException)\r\n            {\r\n                if (_unknownName != null && variableName != _unknownName)\r\n                    throw new ArgumentException(\"Attempted to access more than one unknown variable.\");\r\n                _unknownName = variableName;\r\n                return _selectValue;\r\n            }\r\n            \r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/ApplicativeGroup.cs",
    "content": "﻿using System.Collections.Generic;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    public class ApplicativeGroup\r\n    {\r\n        public readonly List<Statement> Expressions;\r\n\r\n        public ApplicativeGroup(List<Statement> expressions)\r\n        {\r\n            Expressions = expressions;\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/BindProjectPair.cs",
    "content": "﻿using System.Linq.Expressions;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// A pair of (bind, project) expressions that form part of a query expression.\r\n    /// </summary>\r\n    /// <remarks>\r\n    /// Given the following query:\r\n    /// \r\n    /// > from x in a       // (1)\r\n    /// > from y in b(x)    // (2)\r\n    /// > from z in c(x)    // (3)\r\n    /// > select (x, y, z)  // (4)\r\n    /// \r\n    /// It will be desugared into:\r\n    ///\r\n    /// a.SelectMany(                       // Line (1) Initial\r\n    ///     x => b,                         // Line (2) SplitBind \r\n    ///     (x, y) => new { x, y }          // Line (2) Project\r\n    ///  )     \r\n    ///  .SelectMany(\r\n    ///     ti0 => c(ti0.x),                // Line (3) SplitBind\r\n    ///     (ti0, z) => (ti0.x, ti0.y, z)   // Line (4) Final Project\r\n    ///  );\r\n    /// \r\n    /// We can represent any query expression as an initial expression, along with a list of (bind, project) pairs.\r\n    /// </remarks>\r\n    public class BindProjectPair\r\n    {\r\n        public BindProjectPair(LambdaExpression bind, LambdaExpression project)\r\n        {\r\n            Bind = bind;\r\n            Project = project;\r\n        }\r\n\r\n        public bool IsSelect { get; set; }\r\n        public readonly LambdaExpression Bind;\r\n        public readonly LambdaExpression Project;\r\n    }\r\n}"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/BoundExpression.cs",
    "content": "﻿using System.Linq.Expressions;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// An expression that is bound to a particular variable name.\r\n    /// </summary>\r\n    public class BoundExpression\r\n    {\r\n        public readonly LambdaExpression Expression;\r\n        public readonly string BindVariable;\r\n        public readonly int BlockNumber;\r\n\r\n        public BoundExpression(LambdaExpression expression, string bindVariable, int blockNumber)\r\n        {\r\n            Expression = expression;\r\n            BindVariable = bindVariable;\r\n            BlockNumber = blockNumber;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/CacheResult.cs",
    "content": "﻿using System;\r\nusing static HaxlSharp.Internal.Base;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// The result of a cache lookup. \r\n    /// </summary>\r\n    public abstract class CacheResult\r\n    {\r\n        public abstract X Match<X>(Func<Unit, X> notFound, Func<BlockedRequest, X> found);\r\n        public static NotFound NotFound = new NotFound();\r\n        public static Found Found(BlockedRequest request)\r\n        {\r\n            return new Found(request);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// An item matching the cache key was not found.\r\n    /// </summary>\r\n    public class NotFound : CacheResult\r\n    {\r\n        public override X Match<X>(Func<Unit, X> notFound, Func<BlockedRequest, X> found)\r\n        {\r\n            return notFound(UnitVal);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// The item matching the cache key.\r\n    /// </summary>\r\n    public class Found : CacheResult\r\n    {\r\n        private readonly BlockedRequest _blocked;\r\n        public Found(BlockedRequest blocked)\r\n        {\r\n            _blocked = blocked;\r\n        }\r\n\r\n        public override X Match<X>(Func<Unit, X> notFound, Func<BlockedRequest, X> found)\r\n        {\r\n            return found(_blocked);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/ExpressionVariables.cs",
    "content": "﻿using System.Collections.Generic;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// The variables in an expression.\r\n    /// </summary>\r\n    public class ExpressionVariables\r\n    {\r\n        public readonly bool BindsNonTransparentParam;\r\n        public readonly List<string> Bound;\r\n        public readonly List<string> ParameterNames;\r\n\r\n        public ExpressionVariables(bool bindsNonTransparentParam, List<string> bound, List<string> parameterNames)\r\n        {\r\n            BindsNonTransparentParam = bindsNonTransparentParam;\r\n            Bound = bound;\r\n            ParameterNames = parameterNames;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/FreeVariable.cs",
    "content": "﻿\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// A free variable that might come from a transparent identifier.\r\n    /// </summary>\r\n    public class FreeVariable\r\n    {\r\n        public readonly bool FromTransparent;\r\n        public readonly string Name;\r\n        public FreeVariable(string name, bool fromTransparent)\r\n        {\r\n            Name = name;\r\n            FromTransparent = fromTransparent;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/QueryStatement.cs",
    "content": "﻿using System;\r\nusing System.Linq.Expressions;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// Represents a line in a query expression. \r\n    /// </summary>\r\n    public interface QueryStatement\r\n    {\r\n        X Match<X>(Func<BindProjectStatement, X> bind, Func<LetStatement, X> let);\r\n        int BlockNumber { get; set; }\r\n        bool StartsBlock { get; set; }\r\n        bool IsFinal { get; set; }\r\n    }\r\n\r\n    /// <summary>\r\n    /// The variables of each expression in a (bind, project) expression pair.\r\n    /// </summary>\r\n    public class BindProjectStatement : QueryStatement\r\n    {\r\n        public readonly BindProjectPair Expressions;\r\n        public readonly ExpressionVariables BindVariables;\r\n        public readonly ExpressionVariables ProjectVariables;\r\n        public bool IsSelect { get; set; }\r\n\r\n        public BindProjectStatement(BindProjectPair expressions, ExpressionVariables bindVars, ExpressionVariables projectVars)\r\n        {\r\n            Expressions = expressions;\r\n            BindVariables = bindVars;\r\n            ProjectVariables = projectVars;\r\n        }\r\n\r\n        public X Match<X>(Func<BindProjectStatement, X> bind, Func<LetStatement, X> let)\r\n        {\r\n            return bind(this);\r\n        }\r\n\r\n        public int BlockNumber { get; set; }\r\n        public bool StartsBlock { get; set; }\r\n        public bool IsFinal { get; set; }\r\n    }\r\n\r\n    /// <summary>\r\n    /// A let statement, e.g. \r\n    /// > from x in a\r\n    /// > let y = 2\r\n    /// > select x + y;\r\n    /// </summary>\r\n    public class LetStatement : QueryStatement\r\n    {\r\n        public readonly LambdaExpression Expression;\r\n        public readonly ExpressionVariables Variables;\r\n        public readonly string Name;\r\n        public LetStatement(string name, LambdaExpression expression, ExpressionVariables variables)\r\n        {\r\n            Name = name;\r\n            Expression = expression;\r\n            Variables = variables;\r\n        }\r\n\r\n        public X Match<X>(Func<BindProjectStatement, X> bind, Func<LetStatement, X> let)\r\n        {\r\n            return let(this);\r\n        }\r\n\r\n        public int BlockNumber { get; set; }\r\n        public bool StartsBlock { get; set; }\r\n        public bool IsFinal { get; set; }\r\n    }\r\n}"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/ShowList.cs",
    "content": "﻿using System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// Simple pretty printing wrapper around IEnumerable.\r\n    /// </summary>\r\n    public class ShowList<A> : IEnumerable<A>\r\n    {\r\n        public readonly IEnumerable<A> List;\r\n        public ShowList(IEnumerable<A> list)\r\n        {\r\n            List = list;\r\n        }\r\n\r\n        public IEnumerator<A> GetEnumerator()\r\n        {\r\n            return List.GetEnumerator();\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            if (!List.Any()) return \"[]\";\r\n\r\n            var builder = new StringBuilder();\r\n            builder.Append(\"[ \");\r\n            var first = List.First();\r\n            var rest = List.Skip(1);\r\n            builder.Append(first);\r\n            foreach (var item in rest)\r\n            {\r\n                builder.Append($\", {item}\");\r\n            }\r\n            builder.Append(\" ]\");\r\n            return builder.ToString();\r\n        }\r\n\r\n        IEnumerator IEnumerable.GetEnumerator()\r\n        {\r\n            return List.GetEnumerator();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/Statement.cs",
    "content": "﻿using System;\r\n\r\nnamespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// Represents an individual statement expression.\r\n    /// </summary>\r\n    public interface Statement\r\n    {\r\n        X Match<X>(\r\n            Func<BindStatement, X> bind,\r\n            Func<ProjectStatement, X> project\r\n        );\r\n    }\r\n\r\n    /// <summary>\r\n    /// A statement that returns a monad type.\r\n    /// </summary>\r\n    public class BindStatement : Statement\r\n    {\r\n        public readonly BoundExpression Expression;\r\n\r\n        public BindStatement(BoundExpression expression)\r\n        {\r\n            Expression = expression;\r\n        }\r\n\r\n        public X Match<X>(Func<BindStatement, X> bind, Func<ProjectStatement, X> project)\r\n        {\r\n            return bind(this);\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// A statement that returns a non-monadic type.\r\n    /// </summary>\r\n    public class ProjectStatement : Statement\r\n    {\r\n        public readonly BoundExpression Expression;\r\n        public ProjectStatement(BoundExpression expression)\r\n        {\r\n            Expression = expression;\r\n        }\r\n\r\n        public X Match<X>(Func<BindStatement, X> bind, Func<ProjectStatement, X> project)\r\n        {\r\n            return project(this);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Internal/Types/Unit.cs",
    "content": "﻿namespace HaxlSharp.Internal\r\n{\r\n    /// <summary>\r\n    /// The only inhabitant of the Unit type.\r\n    /// </summary>\r\n    public class Unit { }\r\n}"
  },
  {
    "path": "HaxlSharp.Core/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\n\r\n// General Information about an assembly is controlled through the following \r\n// set of attributes. Change these attribute values to modify the information\r\n// associated with an assembly.\r\n[assembly: AssemblyTitle(\"HaxlSharp.Core\")]\r\n[assembly: AssemblyDescription(\"\")]\r\n[assembly: AssemblyConfiguration(\"\")]\r\n[assembly: AssemblyCompany(\"\")]\r\n[assembly: AssemblyProduct(\"HaxlSharp (Core Only)\")]\r\n[assembly: AssemblyCopyright(\"Copyright ©  2016\")]\r\n[assembly: AssemblyTrademark(\"\")]\r\n[assembly: AssemblyCulture(\"\")]\r\n\r\n// Setting ComVisible to false makes the types in this assembly not visible \r\n// to COM components.  If you need to access a type in this assembly from \r\n// COM, set the ComVisible attribute to true on that type.\r\n[assembly: ComVisible(false)]\r\n\r\n// The following GUID is for the ID of the typelib if this project is exposed to COM\r\n[assembly: Guid(\"56487eb5-c699-4eaa-b384-c6f9e64635c5\")]\r\n\r\n// Version information for an assembly consists of the following four values:\r\n//\r\n//      Major Version\r\n//      Minor Version \r\n//      Build Number\r\n//      Revision\r\n//\r\n// You can specify all the values or you can default the Build and Revision Numbers \r\n// by using the '*' as shown below:\r\n// [assembly: AssemblyVersion(\"1.0.*\")]\r\n[assembly: AssemblyVersion(\"0.1.*\")]"
  },
  {
    "path": "HaxlSharp.Core/Response.cs",
    "content": "﻿using System;\r\n\r\nnamespace HaxlSharp\r\n{\r\n    /// <summary>\r\n    /// The result of a primitive request. \r\n    /// </summary>\r\n    public class Response\r\n    {\r\n        public readonly object Value;\r\n        public readonly Type ResultType;\r\n        public Response(object value, Type resultType)\r\n        {\r\n            Value = value;\r\n            ResultType = resultType;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Core/Returns.cs",
    "content": "﻿namespace HaxlSharp\r\n{\r\n    /// <summary>\r\n    /// A request object annotated with a return type.\r\n    /// </summary>\r\n    /// <typeparam name=\"A\">The return type of the request.</typeparam>\r\n    public interface Returns<A> { }\r\n\r\n    public static class RequestExt\r\n    {\r\n        public static Fetch<A> ToFetch<A>(this Returns<A> request)\r\n        {\r\n            return new Request<A>(request);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Fetcher/FetcherBuilder.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing HaxlSharp.Internal;\r\n\r\nnamespace HaxlSharp\r\n{\r\n    /// <summary>\r\n    /// Constructs a fetcher from request handlers.\r\n    /// </summary>\r\n    public class FetcherBuilder\r\n    {\r\n        private readonly Dictionary<Type, Func<BlockedRequest, Response>> _fetchFunctions;\r\n        private readonly Dictionary<Type, Func<BlockedRequest, Task<Response>>> _asyncFetchFunctions;\r\n        private Action<HaxlLogEntry> _logWith;\r\n        public FetcherBuilder()\r\n        {\r\n            _fetchFunctions = new Dictionary<Type, Func<BlockedRequest, Response>>();\r\n            _asyncFetchFunctions = new Dictionary<Type, Func<BlockedRequest, Task<Response>>>();\r\n        }\r\n\r\n        public static FetcherBuilder New()\r\n        {\r\n            return new FetcherBuilder();\r\n        }\r\n\r\n        /// <summary>\r\n        /// Creates untyped fetch function from typed fetch function.\r\n        /// </summary>\r\n        private Func<BlockedRequest, Response> CreateFetchFunc<Req, Res>(Func<Req, Res> fetchFunc) where Req : Returns<Res>\r\n        {\r\n            var resultType = typeof(Res);\r\n            var requestType = typeof(Req);\r\n            Func<BlockedRequest, Response> untypedFetchFunc = request =>\r\n            {\r\n                if (request.RequestType != requestType) throw new ArgumentException(\"Invalid request type\");\r\n                var typedRequest = (Req)request.TypedRequest;\r\n                var result = fetchFunc(typedRequest);\r\n                return new Response(result, typeof(Res));\r\n            };\r\n            return untypedFetchFunc;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Creates untyped async fetch function from typed async fetch function.\r\n        /// </summary>\r\n        private Func<BlockedRequest, Task<Response>> CreateAsyncFetchFunc<Req, Res>(Func<Req, Task<Res>> fetchFunc) where Req : Returns<Res>\r\n        {\r\n            var resultType = typeof(Res);\r\n            var requestType = typeof(Req);\r\n            Func<BlockedRequest, Task<Response>> untypedFetchFunc = async blockedRequest =>\r\n            {\r\n                if (blockedRequest.RequestType != requestType) throw new ArgumentException($\"Request type mismatch: expected '{requestType}', got '{blockedRequest.RequestType}'\");\r\n                var typedRequest = (Req)blockedRequest.TypedRequest;\r\n                var result = await fetchFunc(typedRequest);\r\n                return new Response(result, typeof(Res));\r\n            };\r\n            return untypedFetchFunc;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Throws exception if there's already a handler registered for given type. \r\n        /// </summary>\r\n        private void ThrowIfRegistered(Type requestType)\r\n        {\r\n            if (!_fetchFunctions.ContainsKey(requestType) && !_asyncFetchFunctions.ContainsKey(requestType)) return;\r\n            throw new ArgumentException($\"Attempted to register multiple handlers for request type '{requestType}'\");\r\n        }\r\n\r\n        /// <summary>\r\n        /// Adds a request handler to the fetcher.\r\n        /// </summary>\r\n        public FetcherBuilder FetchRequest<Req, Res>(Func<Req, Res> fetchFunction) where Req : Returns<Res>\r\n        {\r\n            var requestType = typeof(Req);\r\n            ThrowIfRegistered(requestType);\r\n            _fetchFunctions.Add(requestType, CreateFetchFunc(fetchFunction));\r\n            return this;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Adds an async request handler to the fetcher.\r\n        /// </summary>\r\n        public FetcherBuilder FetchRequest<Req, Res>(Func<Req, Task<Res>> fetchFunction) where Req : Returns<Res>\r\n        {\r\n            var requestType = typeof(Req);\r\n            ThrowIfRegistered(requestType);\r\n            _asyncFetchFunctions.Add(requestType, CreateAsyncFetchFunc(fetchFunction));\r\n            return this;\r\n        }\r\n\r\n        public FetcherBuilder LogWith(Action<HaxlLogEntry> logWith)\r\n        {\r\n            _logWith = logWith;\r\n            return this;\r\n        }\r\n\r\n        public HaxlFetcher Create()\r\n        {\r\n            return new HaxlFetcher(_fetchFunctions, _asyncFetchFunctions, _logWith);\r\n        }\r\n    }\r\n}\r\n\r\n"
  },
  {
    "path": "HaxlSharp.Fetcher/HashedRequestKey.cs",
    "content": "﻿using static HaxlSharp.Internal.Base;\r\nusing Newtonsoft.Json;\r\nusing Org.BouncyCastle.Crypto.Digests;\r\nusing Org.BouncyCastle.Utilities.Encoders;\r\n\r\nnamespace HaxlSharp\r\n{\r\n    public class HashedRequestKey : CacheKeyGenerator\r\n    {\r\n        public string ForRequest<A>(Returns<A> request)\r\n        {\r\n            return StaticForRequest(request);\r\n        }\r\n\r\n        private static byte[] Md5Hash(byte[] input)\r\n        {\r\n            // Update the input of MD5\r\n            var md5 = new MD5Digest();\r\n            md5.BlockUpdate(input, 0, input.Length);\r\n\r\n            // Get the output and hash it\r\n            var output = new byte[md5.GetDigestSize()];\r\n            md5.DoFinal(output, 0);\r\n\r\n            return Hex.Encode(output);\r\n        }\r\n\r\n        public static string StaticForRequest<A>(Returns<A> request)\r\n        {\r\n            var json = JsonConvert.SerializeObject(request, request.GetType(), new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All, TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full});\r\n            return compose(ToLowerHexString, Md5Hash, StringBytes)(json);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Fetcher/HaxlFetcher.cs",
    "content": "﻿using System;\r\nusing static HaxlSharp.Internal.Base;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.Linq;\r\nusing HaxlSharp.Internal;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp\r\n{\r\n    public class HaxlFetcher : Fetcher\r\n    {\r\n        private readonly Dictionary<Type, Func<BlockedRequest, Response>> _fetchFunctions;\r\n        private readonly Dictionary<Type, Func<BlockedRequest, Task<Response>>> _asyncFetchFunctions;\r\n        bool isLogging;\r\n\r\n        public HaxlFetcher(Dictionary<Type, Func<BlockedRequest, Response>> fetchFunctions, Dictionary<Type, Func<BlockedRequest, Task<Response>>> asyncFetchFunctions, Action<HaxlLogEntry> onLogEntry = null)\r\n        {\r\n            _fetchFunctions = fetchFunctions;\r\n            _asyncFetchFunctions = asyncFetchFunctions;\r\n            isLogging = onLogEntry != null;\r\n            if (isLogging) OnLogEntry += log => onLogEntry(log);\r\n            else OnLogEntry += log => { };\r\n        }\r\n\r\n        private void ThrowIfUnhandled(BlockedRequest request)\r\n        {\r\n            if (!_fetchFunctions.ContainsKey(request.RequestType) && !_asyncFetchFunctions.ContainsKey(request.RequestType))\r\n            {\r\n                RaiseLogEntry(Error($\"No handler for request type '{request.RequestType}' found.\"));\r\n                throw new Exception($\"No handler for request type '{request.RequestType}' found.\");\r\n            }\r\n        }\r\n\r\n        public async Task<Response> Fetch(BlockedRequest request)\r\n        {\r\n            ThrowIfUnhandled(request);\r\n            if (_fetchFunctions.ContainsKey(request.RequestType))\r\n            {\r\n                var handler = _fetchFunctions[request.RequestType];\r\n                return await Task.Factory.StartNew(() =>\r\n                {\r\n                    var result = handler(request);\r\n                    request.Resolver.SetResult(result.Value);\r\n                    RaiseLogEntry(Info($\"Fetched '{request.BindName}': {result.Value}\"));\r\n                    return result;\r\n                });\r\n            }\r\n            var asyncHandler = _asyncFetchFunctions[request.RequestType];\r\n            var response = await asyncHandler(request);\r\n            request.Resolver.SetResult(response.Value);\r\n            RaiseLogEntry(Info($\"Fetched '{request.BindName}': {response.Value}\"));\r\n            return response;\r\n        }\r\n\r\n        public async Task FetchBatch(IEnumerable<BlockedRequest> requests)\r\n        {\r\n            RaiseLogEntry(Info(\"==== Batch ====\"));\r\n            var tasks = requests.Select(Fetch);\r\n            await Task.WhenAll(tasks);\r\n        }\r\n\r\n        public delegate void HandleLogEntry(HaxlLogEntry logEntry);\r\n\r\n        public event HandleLogEntry OnLogEntry;\r\n\r\n        private void RaiseLogEntry(HaxlLogEntry logEntry)\r\n        {\r\n            if (!isLogging) return;\r\n            OnLogEntry(logEntry);\r\n        }\r\n\r\n        public async Task<A> Fetch<A>(Fetch<A> request)\r\n        {\r\n            var cache = new HaxlCache(new HashedRequestKey());\r\n            return await request.FetchWith(this, cache, RaiseLogEntry);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Fetcher/HaxlSharp.Fetcher.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\r\n  <PropertyGroup>\r\n    <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProjectGuid>{4D87351F-EEE6-4361-B889-D8217EB314AA}</ProjectGuid>\r\n    <OutputType>Library</OutputType>\r\n    <AppDesignerFolder>Properties</AppDesignerFolder>\r\n    <RootNamespace>HaxlSharp</RootNamespace>\r\n    <AssemblyName>HaxlSharp</AssemblyName>\r\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r\n    <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>\r\n    <FileAlignment>512</FileAlignment>\r\n    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <DebugType>full</DebugType>\r\n    <Optimize>false</Optimize>\r\n    <OutputPath>bin\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\r\n    <DebugType>pdbonly</DebugType>\r\n    <Optimize>true</Optimize>\r\n    <OutputPath>bin\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <!-- A reference to the entire .NET Framework is automatically included -->\r\n    <None Include=\"HaxlSharp.Fetcher.nuspec\">\r\n      <SubType>Designer</SubType>\r\n    </None>\r\n    <None Include=\"packages.config\">\r\n      <SubType>Designer</SubType>\r\n    </None>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"HaxlFetcher.cs\" />\r\n    <Compile Include=\"FetcherBuilder.cs\" />\r\n    <Compile Include=\"HashedRequestKey.cs\" />\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\HaxlSharp.Core\\HaxlSharp.Core.csproj\">\r\n      <Project>{56487EB5-C699-4EAA-B384-C6F9E64635C5}</Project>\r\n      <Name>HaxlSharp.Core</Name>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"BouncyCastle.Crypto, Version=1.8.1.0, Culture=neutral, PublicKeyToken=0e99375e54769942\">\r\n      <HintPath>..\\packages\\BouncyCastle.1.8.1\\lib\\BouncyCastle.Crypto.dll</HintPath>\r\n      <Private>True</Private>\r\n    </Reference>\r\n    <Reference Include=\"Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\Newtonsoft.Json.8.0.3\\lib\\portable-net40+sl5+wp80+win8+wpa81\\Newtonsoft.Json.dll</HintPath>\r\n      <Private>True</Private>\r\n    </Reference>\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildExtensionsPath32)\\Microsoft\\Portable\\$(TargetFrameworkVersion)\\Microsoft.Portable.CSharp.targets\" />\r\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r\n       Other similar extension points exist, see Microsoft.Common.targets.\r\n  <Target Name=\"BeforeBuild\">\r\n  </Target>\r\n  <Target Name=\"AfterBuild\">\r\n  </Target>\r\n  -->\r\n</Project>"
  },
  {
    "path": "HaxlSharp.Fetcher/HaxlSharp.Fetcher.nuspec",
    "content": "<?xml version=\"1.0\"?>\r\n<package >\r\n  <metadata>\r\n    <id>$id$</id>\r\n    <version>$version$</version>\r\n    <title>HaxlSharp</title>\r\n    <authors>joashc</authors>\r\n    <projectUrl>https://github.com/joashc/HaxlSharp</projectUrl>\r\n    <requireLicenseAcceptance>false</requireLicenseAcceptance>\r\n    <description>Composable data fetching with automatic concurrency and request deduplication. Installs the core HaxlSharp functionality as well as a fetcher implementation.</description>\r\n    <releaseNotes>Initial release.</releaseNotes>\r\n    <copyright>Copyright © 2016 Joash Chong</copyright>\r\n  </metadata>\r\n</package>"
  },
  {
    "path": "HaxlSharp.Fetcher/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\n\r\n// General Information about an assembly is controlled through the following \r\n// set of attributes. Change these attribute values to modify the information\r\n// associated with an assembly.\r\n[assembly: AssemblyTitle(\"HaxlSharp.Fetcher\")]\r\n[assembly: AssemblyDescription(\"\")]\r\n[assembly: AssemblyConfiguration(\"\")]\r\n[assembly: AssemblyCompany(\"\")]\r\n[assembly: AssemblyProduct(\"HaxlSharp.Fetcher\")]\r\n[assembly: AssemblyCopyright(\"Copyright ©  2016\")]\r\n[assembly: AssemblyTrademark(\"\")]\r\n[assembly: AssemblyCulture(\"\")]\r\n\r\n// Setting ComVisible to false makes the types in this assembly not visible \r\n// to COM components.  If you need to access a type in this assembly from \r\n// COM, set the ComVisible attribute to true on that type.\r\n[assembly: ComVisible(false)]\r\n\r\n// The following GUID is for the ID of the typelib if this project is exposed to COM\r\n[assembly: Guid(\"4d87351f-eee6-4361-b889-d8217eb314aa\")]\r\n\r\n// Version information for an assembly consists of the following four values:\r\n//\r\n//      Major Version\r\n//      Minor Version \r\n//      Build Number\r\n//      Revision\r\n//\r\n// You can specify all the values or you can default the Build and Revision Numbers \r\n// by using the '*' as shown below:\r\n// [assembly: AssemblyVersion(\"1.0.*\")]\r\n[assembly: AssemblyVersion(\"0.1.*\")]\r\n"
  },
  {
    "path": "HaxlSharp.Fetcher/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n  <package id=\"BouncyCastle\" version=\"1.8.1\" targetFramework=\"portable45-net45+win8\" />\r\n  <package id=\"Newtonsoft.Json\" version=\"8.0.3\" targetFramework=\"portable45-net45+win8\" />\r\n</packages>"
  },
  {
    "path": "HaxlSharp.Test/ApplicativeRewriteTest.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Threading.Tasks;\r\nusing System.Linq;\r\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\r\nusing System.Diagnostics;\r\nusing HaxlSharp.Internal;\r\nusing static HaxlSharp.Test.Blog;\r\nusing static HaxlSharp.Internal.Base;\r\n\r\nnamespace HaxlSharp.Test\r\n{\r\n    [TestClass]\r\n    public class ApplicativeRewriteTest\r\n    {\r\n        public HaxlFetcher fetcher = Fetcher();\r\n\r\n        [TestMethod]\r\n        public async Task SingleFetch_ShouldHaveOneBatch()\r\n        {\r\n            var postIds = FetchAllPostIds();\r\n            await fetcher.Fetch(postIds);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task SelectFetch()\r\n        {\r\n            var fetch = FetchAllPostIds();\r\n            var postIds = await fetcher.Fetch(fetch);\r\n            var first = postIds.First();\r\n\r\n            var fetch1 = from ids in FetchAllPostIds().Select(list => list.Select(x => x + 1))\r\n                         from somethingElse in FetchAllPostIds()\r\n                         select ids.First();\r\n            var firstPlus1 = await fetcher.Fetch(fetch1);\r\n            Assert.AreEqual(first + 1, firstPlus1);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task SelectFetchFinal()\r\n        {\r\n            var fetch = FetchAllPostIds();\r\n            var postIds = await fetcher.Fetch(fetch);\r\n            var first = postIds.First();\r\n\r\n            var fetch1 = from ids in FetchAllPostIds().Select(list => list.Select(x => x + 1))\r\n                         select ids.First();\r\n            var firstPlus1 = await fetcher.Fetch(fetch1);\r\n            Assert.AreEqual(first + 1, firstPlus1);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task SelectLetFetch()\r\n        {\r\n            var fetch = FetchAllPostIds();\r\n            var postIds = await fetcher.Fetch(fetch);\r\n            var first = postIds.First();\r\n\r\n            var fetch1 = from ids in FetchAllPostIds().Select(list => list.Select(x => x + 1))\r\n                         let first1 = ids.First()\r\n                         from ids2 in FetchAllPostIds()\r\n                         select first1;\r\n            var firstPlus1 = await fetcher.Fetch(fetch1);\r\n            Assert.AreEqual(first + 1, firstPlus1);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task SelectLetFetchExtended()\r\n        {\r\n            var fetch = FetchAllPostIds();\r\n            var postIds = await fetcher.Fetch(fetch);\r\n            var first = postIds.First();\r\n\r\n            var fetch1 = from ids in FetchAllPostIds().Select(list => list.Select(x => x + 1))\r\n                         let first1 = ids.First()\r\n                         from ids2 in FetchAllPostIds()\r\n                         from ids3 in FetchAllPostIds()\r\n                         select first1 + ids.First();\r\n            var firstPlus1 = await fetcher.Fetch(fetch1);\r\n            Assert.AreEqual(first + 1 + 1, firstPlus1);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task SequentialFetch_ShouldHaveTwoBatches()\r\n        {\r\n            var firstPostInfo = from postIds in FetchAllPostIds()\r\n                                from firstInfo in FetchPostInfo(postIds.First())\r\n                                select firstInfo;\r\n            var result = await fetcher.Fetch(firstPostInfo);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task SequentialFetch_ShouldHaveTwoBatchesRepeat()\r\n        {\r\n            var firstPostInfo = from postIds in FetchAllPostIds()\r\n                                from firstInfo in FetchPostInfo(postIds.Skip(1).First())\r\n                                select firstInfo;\r\n            var result = await fetcher.Fetch(firstPostInfo);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task Sequence_ShouldBeApplicative()\r\n        {\r\n            var getAllPostsInfo =\r\n                from postIds in FetchAllPostIds()\r\n                from postInfo in postIds.SelectFetch(GetPostDetails)\r\n                select postInfo;\r\n            var result = await fetcher.Fetch(getAllPostsInfo);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task Sequence_ShouldBeApplicativeAgain()\r\n        {\r\n            var getAllPostsInfo =\r\n                from postIds in FetchAllPostIds()\r\n                from postInfo in postIds.SelectFetch(GetPostDetails)\r\n                select postInfo;\r\n            var result = await fetcher.Fetch(getAllPostsInfo);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task Sequence_ShouldBeApplicativeAgainAddOne()\r\n        {\r\n            var getAllPostsInfo =\r\n                from postIds in FetchAllPostIds()\r\n                from postInfo in postIds.Select(x => x + 1).SelectFetch(GetPostDetails)\r\n                select postInfo;\r\n            var result = await fetcher.Fetch(getAllPostsInfo);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task SharedDependency()\r\n        {\r\n            var fetch =\r\n                from postIds in FetchAllPostIds()\r\n                from postInfo in postIds.SelectFetch(Blog.FetchPostInfo)\r\n                from firstPostInfo in FetchPostInfo(postIds.First())\r\n                select firstPostInfo;\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task JustSequence()\r\n        {\r\n            var sequence = Enumerable.Range(0, 10).SelectFetch(Blog.FetchPostInfo);\r\n            var result = await fetcher.Fetch(sequence);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task GetDuplicateFriends()\r\n        {\r\n            var fetch = from ids in FetchTwoLatestPosts()\r\n                        from friends in FetchPostAuthorFriends(ids.Item1)\r\n                        from friends2 in FetchPostAuthorFriends(ids.Item2)\r\n                        select ShowList(friends.Concat(friends2));\r\n            var result = await fetcher.Fetch(fetch);\r\n            ;\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task GetFriends()\r\n        {\r\n            var fetch = from info in FetchPostInfo(3)\r\n                        from author in GetPerson(info.AuthorId)\r\n                        from friends in author.BestFriendIds.SelectFetch(Blog.GetPerson)\r\n                        select ShowList(friends);\r\n            var result = await fetcher.Fetch(fetch);\r\n            ;\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task GetNull()\r\n        {\r\n            var fetch = from info in FetchPostInfo(3)\r\n                        from author in FetchNullPerson()\r\n                        select author;\r\n            var result = await fetcher.Fetch(fetch);\r\n            ;\r\n        }\r\n\r\n\r\n        [TestMethod]\r\n        public async Task LetNotation_Applicative()\r\n        {\r\n\r\n            var id = 0;\r\n            var fetch = from postInfo in FetchPostInfo(id)\r\n                        let id2 = 1 + postInfo.PostId\r\n                        from postInfo2 in FetchPostInfo(id2)\r\n                        select postInfo2.PostTopic + id2;\r\n\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task FinalLetNotation_Applicative()\r\n        {\r\n\r\n            var id = 0;\r\n            var fetch = from postInfo in FetchPostInfo(id)\r\n                        from postInfo2 in FetchPostInfo(1)\r\n                        let id2 = 1 + postInfo.PostId\r\n                        select postInfo2.PostTopic + id2;\r\n\r\n            var result = await fetcher.Fetch(fetch);\r\n            Assert.AreEqual(\"Topic 11\", result);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task FinalLetNotation()\r\n        {\r\n            var id = 0;\r\n            var fetch = from postInfo in FetchPostInfo(id)\r\n                        let x = 3\r\n                        from postInfo2 in FetchPostInfo(1)\r\n                        let id2 = 1 + postInfo.PostId + 3\r\n                        select postInfo2.PostTopic + id2 + x;\r\n\r\n            var result = await fetcher.Fetch(fetch);\r\n            Assert.AreEqual(\"Topic 143\", result);\r\n\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task FinalLetNotation_ApplicativeExtended()\r\n        {\r\n\r\n            var id = 0;\r\n            var fetch = from postInfo in FetchPostInfo(id)\r\n                        from postInfo2 in FetchPostInfo(1)\r\n                        from postInfo3 in FetchPostInfo(postInfo2.PostId)\r\n                        let id2 = 1 + postInfo.PostId + postInfo3.PostId\r\n                        select postInfo2.PostTopic + id2;\r\n\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task MultipleLetNotation_Applicative()\r\n        {\r\n\r\n            var id = 0;\r\n            var let = FetchPostInfo(id).Select(info => info.PostId);\r\n            var fetch = from postInfo in FetchPostInfo(id)\r\n                        let id2 = 1 + postInfo.PostId\r\n                        let id3 = 4\r\n                        from postInfo2 in FetchPostInfo(id2)\r\n                        select postInfo2.PostTopic + id2 + id3;\r\n\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task TwoLatestExample()\r\n        {\r\n            var fetch = from latest in FetchTwoLatestPosts()\r\n                        from first in GetPostDetails(latest.Item1)\r\n                        from second in GetPostDetails(latest.Item2)\r\n                        select ShowList(new List<PostDetails> { first, second });\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task DuplicateNestedNames()\r\n        {\r\n            var nested = from x in FetchTwoLatestPosts()\r\n                         from z in FetchTwoLatestPosts()\r\n                         from y in GetPostDetails(x.Item1)\r\n                         select $\"[Nested: {y.Content}]\";\r\n\r\n            var nested2 = from x in nested\r\n                          from y in nested\r\n                          select $\"[Nested2: [ {x}, {y} ]\";\r\n            var global = new { x = 3 };\r\n\r\n            var fetch = from x in nested2\r\n                        from y in nested2\r\n                        from z in nested\r\n                        let id2 = global.x\r\n                        from n in nested\r\n                        select $\"Fetch: [ {x}, {y} ]\";\r\n            var result = await fetcher.Fetch(fetch);\r\n            Assert.AreEqual(\r\n                \"Fetch: [ [Nested2: [ [Nested: Post 3], [Nested: Post 3] ], [Nested2: [ [Nested: Post 3], [Nested: Post 3] ] ]\",\r\n                result\r\n            );\r\n\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task NoNesting()\r\n        {\r\n            var fetch = from x in FetchTwoLatestPosts()\r\n                        from y in FetchTwoLatestPosts()\r\n                        from z in FetchTwoLatestPosts()\r\n                        from n in FetchTwoLatestPosts()\r\n                        select $\"Fetch: [ {x}, {y} ]\";\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task NestedLet()\r\n        {\r\n            var nested = from x in GetPostDetails(3)\r\n                         from y in GetPostDetails(4)\r\n                         select $\"[ {x.Content}, {y.Content} ]\";\r\n            var fetch = from x in nested\r\n                        let id = 3\r\n                        from y in GetPostDetails(id)\r\n                        select x + y.Content;\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task DuplicateNested()\r\n        {\r\n            var nested = from x in GetPostDetails(3)\r\n                         from y in GetPostDetails(4)\r\n                         select $\"[ {x.Content}, {y.Content} ]\";\r\n\r\n            var nested2 = from x in nested\r\n                          from z in nested\r\n                          select $\"{x}, {z}\";\r\n\r\n            var fetch = from x in nested2\r\n                        from y in nested\r\n                        select $\"{x}, {y}\";\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task TwoLatestExampleAgain()\r\n        {\r\n            var fetch = from latest in FetchTwoLatestPosts()\r\n                        from first in GetPostDetails(latest.Item1 + 1)\r\n                        from second in GetPostDetails(latest.Item2 + 2)\r\n                        select new List<PostDetails> { first, second };\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task FetchDetails()\r\n        {\r\n            var fetch = GetPostDetails(1);\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task FetchDetails2()\r\n        {\r\n            var fetch = from info in FetchPostInfo(2)\r\n                        select new PostDetails(info, \"Content\");\r\n            var result = await fetcher.Fetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task TransparentAccess()\r\n        {\r\n            var fetch = from latest in FetchTwoLatestPosts()\r\n                        from something in FetchPostInfo(1)\r\n                        from somethingElse in FetchPostInfo(2)\r\n                        from three in FetchPostInfo(3)\r\n                        from newPost in FetchPostInfo(latest.Item1)\r\n                        select newPost;\r\n            var result = await BlogFetch(fetch);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task Deduplication()\r\n        {\r\n            var fetch = from postIds in FetchDuplicatePosts()\r\n                        from details in postIds.SelectFetch(GetPostDetails)\r\n                        select ShowList(details);\r\n            var result = await BlogFetch(fetch);\r\n        }\r\n\r\n        private Task<A> BlogFetch<A>(Fetch<A> request)\r\n        {\r\n            return fetcher.Fetch(request);\r\n        }\r\n\r\n        [TestMethod]\r\n        public async Task WithoutApplicative()\r\n        {\r\n            var latest = await BlogFetch(FetchTwoLatestPosts());\r\n            var first = await BlogFetch(FetchPostInfo(latest.Item1));\r\n            var firstContent = await BlogFetch(FetchPostContent(1));\r\n            var second = await BlogFetch(FetchPostInfo(latest.Item2));\r\n            var secondContent = await BlogFetch(FetchPostContent(latest.Item2));\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Test/BindExpressionParseTest.cs",
    "content": "﻿using System;\r\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\r\nusing static HaxlSharp.Internal.Base;\r\n\r\nnamespace HaxlSharp.Test\r\n{\r\n    [TestClass]\r\n    public class BindExpressionParseTest\r\n    {\r\n        [TestMethod]\r\n        public void ParseBindVar()\r\n        {\r\n            var blockNumber = GetBlockNumber(\"(0) int\");\r\n            Assert.AreEqual(0, blockNumber);\r\n        }\r\n\r\n        [TestMethod]\r\n        public void ParseBigBindVar()\r\n        {\r\n            var blockNumber = GetBlockNumber(\"(7489230) int\");\r\n            Assert.AreEqual(7489230, blockNumber);\r\n        }\r\n\r\n        [TestMethod]\r\n        public void InvalidParse()\r\n        {\r\n            try\r\n            {\r\n                var blockNumber = GetBlockNumber(\"((7489230)\");\r\n                Assert.Fail(\"No exception thrown.\");\r\n            }\r\n            catch (ArgumentException)\r\n            {\r\n                // pass\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Test/Blog.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing static HaxlSharp.Internal.Base;\r\nusing HaxlSharp.Internal;\r\nusing System.Diagnostics;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp.Test\r\n{\r\n    public class Post\r\n    {\r\n        public string Title { get; set; }\r\n        public string Content { get; set; }\r\n        public int PostId { get; set; }\r\n    }\r\n\r\n    public class FetchPosts : Returns<IEnumerable<int>> { }\r\n\r\n    public class FetchDuplicatePosts : Returns<ShowList<int>> { }\r\n\r\n    public class GetPerson : Returns<Person>\r\n    {\r\n        public readonly int PersonId;\r\n        public GetPerson(int personId)\r\n        {\r\n            PersonId = personId;\r\n        }\r\n    }\r\n\r\n    public class GetNullPerson : Returns<Person> { }\r\n\r\n    public class FetchPostInfo : Returns<PostInfo>\r\n    {\r\n        public readonly int PostId;\r\n        public FetchPostInfo(int postId)\r\n        {\r\n            PostId = postId;\r\n        }\r\n    }\r\n\r\n    public class GetTwoLatestPosts : Returns<Tuple<int, int>> { }\r\n\r\n    public class FetchPostContent : Returns<string>\r\n    {\r\n        public readonly int PostId;\r\n        public FetchPostContent(int postId)\r\n        {\r\n            PostId = postId;\r\n        }\r\n    }\r\n\r\n    public class FetchPostViews : Returns<int>\r\n    {\r\n        public readonly int PostId;\r\n        public FetchPostViews(int postId)\r\n        {\r\n            PostId = postId;\r\n        }\r\n    }\r\n\r\n    public class Person\r\n    {\r\n        public int PersonId;\r\n        public string Name;\r\n        public IEnumerable<int> BestFriendIds;\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"Person {{ PersonId: {PersonId}, Name: {Name}, BestFriendIds: {BestFriendIds}  }}\";\r\n        }\r\n    }\r\n\r\n\r\n\r\n    public static class Blog\r\n    {\r\n        public static List<string> Names = new List<string>\r\n        {\r\n            \"Cherry Greenburg\",\r\n            \"Alison Herald\",\r\n            \"Michal Zakrzewski\",\r\n            \"Chance Kehoe\",\r\n            \"Delaine Crago\",\r\n            \"Sabina Barrs\",\r\n            \"Peg Delosh\",\r\n            \"Johnie Wengerd\",\r\n            \"Shayne Knauer\",\r\n            \"Tyson Dave\",\r\n            \"Shandra Hanlin\",\r\n            \"Rey Pita\",\r\n            \"Jacquelyn Bivona\",\r\n            \"Cristal Hornak\",\r\n            \"Julieta Kilbane\",\r\n            \"Terry Cavin\",\r\n            \"Peppa Pig\",\r\n            \"Charity Gadsden\",\r\n            \"Antione Domingo\",\r\n            \"Corazon Benito\",\r\n            \"Tianna Bratton\",\r\n        };\r\n\r\n\r\n        public static HaxlFetcher Fetcher()\r\n        {\r\n            return FetcherBuilder.New()\r\n\r\n                .FetchRequest<FetchPosts, IEnumerable<int>>(_ =>\r\n                {\r\n                    return ShowList(Enumerable.Range(0, 10));\r\n                })\r\n\r\n                .FetchRequest<FetchDuplicatePosts, ShowList<int>>(_ =>\r\n                {\r\n                    return ShowList(Enumerable.Repeat(1, 10));\r\n                })\r\n\r\n                .FetchRequest<FetchPostInfo, PostInfo>(req =>\r\n                {\r\n                    var postId = req.PostId;\r\n                    return new PostInfo(postId, DateTime.Today.AddDays(-postId), $\"Topic {postId % 3}\", (postId * 33) % 20);\r\n                })\r\n\r\n                .FetchRequest<FetchPostContent, string>(req =>\r\n                {\r\n                    return $\"Post {req.PostId}\";\r\n                })\r\n\r\n                .FetchRequest<FetchPostViews, int>(req =>\r\n                {\r\n                    return (req.PostId * 33) % 53;\r\n                })\r\n\r\n                .FetchRequest<GetNullPerson, Person>(async req =>\r\n               {\r\n                   await Task.Delay(10);\r\n                   return null;\r\n               })\r\n\r\n                .FetchRequest<GetPerson, Person>(req =>\r\n               {\r\n                   var nameIndex = (req.PersonId * 33) % 20;\r\n                   return new Person\r\n                   {\r\n                       Name = Names.ElementAt(nameIndex),\r\n                       BestFriendIds = ShowList(new List<int>\r\n                        {\r\n                            (nameIndex + 3) % 20,\r\n                            (nameIndex + 5) % 20,\r\n                            (nameIndex + 7) % 20\r\n                        }),\r\n                       PersonId = req.PersonId\r\n                   };\r\n\r\n               })\r\n\r\n                .FetchRequest<GetTwoLatestPosts, Tuple<int, int>>(req =>\r\n                {\r\n                    return new Tuple<int, int>(3, 4);\r\n                })\r\n                .LogWith(log => Debug.WriteLine(log.ToDefaultString()))\r\n                .Create();\r\n        }\r\n\r\n        public static Fetch<Tuple<int, int>> FetchTwoLatestPosts()\r\n        {\r\n            return new GetTwoLatestPosts().ToFetch();\r\n        }\r\n\r\n        public static Fetch<ShowList<int>> FetchDuplicatePosts()\r\n        {\r\n            return new FetchDuplicatePosts().ToFetch();\r\n        }\r\n\r\n        public static Fetch<IEnumerable<int>> FetchAllPostIds()\r\n        {\r\n            return new FetchPosts().ToFetch();\r\n        }\r\n\r\n        public static Fetch<PostInfo> FetchPostInfo(int postId)\r\n        {\r\n            return new FetchPostInfo(postId).ToFetch();\r\n        }\r\n\r\n        public static Fetch<string> FetchPostContent(int postId)\r\n        {\r\n            return new FetchPostContent(postId).ToFetch();\r\n        }\r\n\r\n        public static Fetch<int> GetFirstPostId()\r\n        {\r\n            return from posts in GetAllPostInfo()\r\n                   select posts.OrderByDescending(p => p.PostDate).First().PostId;\r\n        }\r\n\r\n        public static Fetch<int> FetchPostViews(int postId)\r\n        {\r\n            return new FetchPostViews(postId).ToFetch();\r\n        }\r\n\r\n        public static Fetch<ShowList<Person>> FetchPostAuthorFriends(int postId)\r\n        {\r\n            return from info in FetchPostInfo(postId)\r\n                   from author in GetPerson(info.AuthorId)\r\n                   from friends in author.BestFriendIds.SelectFetch(Blog.GetPerson)\r\n                   select ShowList(friends);\r\n        }\r\n\r\n        public static Fetch<Person> FetchNullPerson()\r\n        {\r\n            return new GetNullPerson().ToFetch();\r\n        }\r\n\r\n        public static Fetch<PostDetails> GetPostDetails(int postId)\r\n        {\r\n            var x = from info in FetchPostInfo(postId)\r\n                    from content in FetchPostContent(info.PostId)\r\n                    select new PostDetails(info, content);\r\n            return x;\r\n        }\r\n\r\n        public static Fetch<IEnumerable<PostInfo>> GetAllPostInfo()\r\n        {\r\n            return from postIds in FetchAllPostIds()\r\n                   from postInfo in postIds.SelectFetch(FetchPostInfo)\r\n                   select postInfo;\r\n        }\r\n\r\n        public static Fetch<Person> GetPerson(int personId)\r\n        {\r\n            return new GetPerson(personId).ToFetch();\r\n        }\r\n\r\n        public static Fetch<IEnumerable<string>> RecentPostContent()\r\n        {\r\n            return from posts in GetAllPostInfo()\r\n                   from recentContent in\r\n                        posts.OrderByDescending(p => p.PostDate)\r\n                             .Take(4)\r\n                             .SelectFetch(pi => FetchPostContent(pi.PostId))\r\n                   select recentContent;\r\n        }\r\n\r\n    }\r\n\r\n    public class PostDetails\r\n    {\r\n        public PostInfo Info;\r\n        public string Content;\r\n        public PostDetails(PostInfo info, string content)\r\n        {\r\n            Info = info;\r\n            Content = content;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"PostDetails {{ Info: {Info}, Content: '{Content}' }}\";\r\n        }\r\n    }\r\n\r\n\r\n\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Test/ExpressionTests.cs",
    "content": "﻿using Microsoft.VisualStudio.TestTools.UnitTesting;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing HaxlSharp.Internal;\r\n\r\nnamespace HaxlSharp.Test\r\n{\r\n    public class Nested\r\n    {\r\n        public int x => 99;\r\n    }\r\n\r\n\r\n    [TestClass]\r\n    public class ExpressionSplitTests\r\n    {\r\n        public const int global = 2;\r\n        public static FetchResult<int> a = new FetchResult<int>(global);\r\n        public static FetchResult<int> b = new FetchResult<int>(3);\r\n        public static Func<int, FetchResult<int>> c = i => new FetchResult<int>(i);\r\n        public static Func<int, int, FetchResult<int>> c2 = (i, i2) => new FetchResult<int>(i);\r\n        public static Func<int, FetchResult<int>> d = i => new FetchResult<int>(i);\r\n        public static Nested nested = new Nested();\r\n\r\n        public static int CountAt(List<ApplicativeGroup> split, int i)\r\n        {\r\n            return split.ElementAt(i).Expressions.Count();\r\n        }\r\n\r\n        public static int SplitCount(List<ApplicativeGroup> split)\r\n        {\r\n            return split.Count(s => s.Expressions.Any(e => e.Match(bind => true, project => false)));\r\n        }\r\n\r\n        public static int ProjectCount(List<ApplicativeGroup> split)\r\n        {\r\n            return split.Count(s => s.Expressions.Any(e => e.Match(bind => false, project => true)));\r\n        }\r\n\r\n        public static List<ApplicativeGroup> Split<A>(Fetch<A> fetch)\r\n        {\r\n            var type = fetch.GetType();\r\n            Assert.IsTrue(type.GetGenericTypeDefinition() == typeof(Bind<,,>));\r\n            return SplitApplicative.SplitBind(fetch.CollectedExpressions, fetch.Initial);\r\n        }\r\n\r\n        [TestMethod]\r\n        public void DuplicateVariableNames()\r\n        {\r\n            // We've got two variables of different type named 'x'.\r\n\r\n            var nested =     from x in new FetchResult<string>(\"1\")           // Group 0.1\r\n                             // split                                         // =========\r\n                             from za in c(int.Parse(x))                       // Group 1.1\r\n                             from ya in b                                     // Group 1.2\r\n                             //projection                                     // =========\r\n                             select ya;                                       // Group 2.1 (Projection)\r\n            var expression = from x in nested                                 // \r\n                             // split                                 \t\t  // =========\r\n                             from z in c(x)                           \t\t  // Group 3.1\r\n                             from y in b                              \t\t  // Group 3.2\r\n                             // split                                 \t\t  // =========\r\n                             from w in d(y)                           \t\t  // Group 4.1\r\n                             // projection                            \t\t  // =========\r\n                             select x + y + z + w;                    \t\t  // Group 5.1 (Projection)\r\n\r\n            var split = Split(expression);\r\n            Assert.AreEqual(4, SplitCount(split));\r\n            Assert.AreEqual(2, ProjectCount(split));\r\n            Assert.AreEqual(1, CountAt(split, 0));\r\n            Assert.AreEqual(2, CountAt(split, 1));\r\n            Assert.AreEqual(1, CountAt(split, 2)); \r\n            Assert.AreEqual(2, CountAt(split, 3));\r\n            Assert.AreEqual(1, CountAt(split, 4));\r\n        }\r\n\r\n        [TestMethod]\r\n        public void SplitWithApplicativeProject()\r\n        {\r\n            var nested = from x in a\r\n                         from y in b\r\n                         select 3;\r\n\r\n            var fetch = from x in nested\r\n                        from y in a\r\n                        from z in b\r\n                        select x + y + z;\r\n\r\n            var split = Split(fetch);\r\n            Assert.AreEqual(1, SplitCount(split));\r\n        }\r\n\r\n        [TestMethod]\r\n        public void ExpressionTest()\r\n        {\r\n            var nested =     from xa in new FetchResult<int>(66)        // Group 0.1\r\n                             // split                                   // =========\r\n                             from za in c(xa)                           // Group 1.1\r\n                             from ya in b                               // Group 1.2\r\n                             //projection                               // =========\r\n                             select xa + ya + za;                       // Group 2.1 (Projection)\r\n            var expression = from x in nested                           // \r\n                             // split                                   // =========\r\n                             from z in c(x)                             // Group 3.1\r\n                             from y in b                                // Group 3.2\r\n                             // split                                   // =========\r\n                             from w in d(y)                             // Group 4.1\r\n                             // projection                              // =========\r\n                             select x + y + z + w;                      // Group 5.1 (Projection)\r\n\r\n            var split = Split(expression);\r\n            Assert.AreEqual(4, SplitCount(split));\r\n            Assert.AreEqual(2, ProjectCount(split));\r\n            Assert.AreEqual(1, CountAt(split, 0));\r\n            Assert.AreEqual(2, CountAt(split, 1));\r\n            Assert.AreEqual(1, CountAt(split, 2)); \r\n            Assert.AreEqual(2, CountAt(split, 3));\r\n            Assert.AreEqual(1, CountAt(split, 4));\r\n        }\r\n\r\n        [TestMethod]\r\n        public void ExpressionTest2()\r\n        {\r\n            var expression = from x in a\r\n                             from y in new FetchResult<int>(nested.x)\r\n                                 // split\r\n                             from z in c2(x, y)\r\n                             select x + y + z;\r\n            var split = Split(expression);\r\n            Assert.AreEqual(2, SplitCount(split));\r\n            Assert.AreEqual(2, CountAt(split, 0));\r\n            Assert.AreEqual(1, CountAt(split, 1));\r\n        }\r\n\r\n        [TestMethod]\r\n        public void ExpressionTest3()\r\n        {\r\n            var expression = from x in a\r\n                                 // split\r\n                             from y in c(x)\r\n                             from z in c(x)\r\n                             select x + y + z;\r\n            var split = Split(expression);\r\n            Assert.AreEqual(2, SplitCount(split));\r\n            Assert.AreEqual(1, CountAt(split, 0));\r\n            Assert.AreEqual(2, CountAt(split, 1));\r\n        }\r\n\r\n        [TestMethod]\r\n        public void ExpressionTest4()\r\n        {\r\n            var expression = from f in a\r\n                             from x in a\r\n                                 // split\r\n                             from y in c(x)\r\n                             from z in c(nested.x)\r\n                             select x + y + z;\r\n            var split = Split(expression);\r\n            Assert.AreEqual(2, SplitCount(split));\r\n            Assert.AreEqual(2, CountAt(split, 0));\r\n            Assert.AreEqual(2, CountAt(split, 1));\r\n        }\r\n\r\n        [TestMethod]\r\n        public void ExpressionTest5()\r\n        {\r\n            var expression = from x in a\r\n                             from z in c(nested.x)\r\n                                 // split\r\n                             from y in c(x + 3)\r\n                             select x + y + z;\r\n            var split = Split(expression);\r\n            Assert.AreEqual(2, SplitCount(split));\r\n            Assert.AreEqual(2, CountAt(split, 0));\r\n            Assert.AreEqual(1, CountAt(split, 1));\r\n        }\r\n\r\n        [TestMethod]\r\n        public void ExpressionTest6()\r\n        {\r\n            var expression = from z in c(nested.x)\r\n                             from x in a\r\n                                 // split\r\n                             from y in c(x + 3)\r\n                             select x + y + z;\r\n            var split = Split(expression);\r\n            Assert.AreEqual(2, SplitCount(split));\r\n            Assert.AreEqual(2, CountAt(split, 0));\r\n            Assert.AreEqual(1, CountAt(split, 1));\r\n\r\n        }\r\n\r\n        [TestMethod]\r\n        public void LetTest()\r\n        {\r\n            var expression = from x in a\r\n                             let q = x + 3\r\n                             from z in c(q)\r\n                             from y in c(q + 3)\r\n                             select x + y + z;\r\n            var split = Split(expression);\r\n        }\r\n\r\n        [TestMethod]\r\n        public void NestedQuery()\r\n        {\r\n            var expression = from x in (from x in a select x + 1) \r\n                             from y in b\r\n                                 //split\r\n                             from z in c(x)\r\n                             from w in d(y)\r\n                             select x + y + z + w;\r\n            var split = Split(expression);\r\n\r\n        }\r\n\r\n        [TestMethod]\r\n        public void SequenceRewrite()\r\n        {\r\n            var list = Enumerable.Range(0, 10);\r\n            Func<int, FetchResult<int>> mult10 = x => new FetchResult<int>(x * 10);\r\n            var expression = from x in new FetchResult<IEnumerable<int>>(list)\r\n                             from multiplied in x.SelectFetch(mult10)\r\n                             from added in x.SelectFetch(num => new FetchResult<int>(num + 1))\r\n                             select added.Concat(multiplied);\r\n\r\n            var split = Split(expression);\r\n            Assert.AreEqual(2, SplitCount(split));\r\n            Assert.AreEqual(1, CountAt(split, 0));\r\n            Assert.AreEqual(2, CountAt(split, 1));\r\n        }\r\n\r\n\r\n        [TestMethod]\r\n        public void SequenceRewriteConcurrent()\r\n        {\r\n            var list = Enumerable.Range(0, 1000);\r\n            Func<int, FetchResult<int>> mult10 = x => new FetchResult<int>(x * 10);\r\n            var expression = from x in new FetchResult<IEnumerable<int>>(list)\r\n                             from multiplied in x.SelectFetch(mult10)\r\n                             from added in x.SelectFetch(num => new FetchResult<int>(num))\r\n                             select added.Concat(multiplied);\r\n\r\n            var split = Split(expression);\r\n            Assert.AreEqual(2, SplitCount(split));\r\n            Assert.AreEqual(1, CountAt(split, 0));\r\n            Assert.AreEqual(2, CountAt(split, 1));\r\n        }\r\n\r\n        [TestMethod]\r\n        public void OneLiner()\r\n        {\r\n            var oneLine = from x in new FetchResult<int>(3)\r\n                          select x + 1;\r\n        }\r\n\r\n        [TestMethod]\r\n        public void SelectTest()\r\n        {\r\n            var number = new FetchResult<int>(3);\r\n            var plusOne = number.Select(num => num + 1);\r\n            var plusTwo = plusOne.Select(num => num + 1);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "HaxlSharp.Test/HaxlSharp.Test.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProjectGuid>{B62BE199-4FAB-41BF-BB52-A194E7E8106D}</ProjectGuid>\r\n    <OutputType>Library</OutputType>\r\n    <AppDesignerFolder>Properties</AppDesignerFolder>\r\n    <RootNamespace>HaxlSharp.Test</RootNamespace>\r\n    <AssemblyName>HaxlSharp.Test</AssemblyName>\r\n    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>\r\n    <FileAlignment>512</FileAlignment>\r\n    <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\r\n    <VisualStudioVersion Condition=\"'$(VisualStudioVersion)' == ''\">10.0</VisualStudioVersion>\r\n    <VSToolsPath Condition=\"'$(VSToolsPath)' == ''\">$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)</VSToolsPath>\r\n    <ReferencePath>$(ProgramFiles)\\Common Files\\microsoft shared\\VSTT\\$(VisualStudioVersion)\\UITestExtensionPackages</ReferencePath>\r\n    <IsCodedUITest>False</IsCodedUITest>\r\n    <TestProjectType>UnitTest</TestProjectType>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <DebugType>full</DebugType>\r\n    <Optimize>false</Optimize>\r\n    <OutputPath>bin\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\r\n    <DebugType>pdbonly</DebugType>\r\n    <Optimize>true</Optimize>\r\n    <OutputPath>bin\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"System\" />\r\n  </ItemGroup>\r\n  <Choose>\r\n    <When Condition=\"('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'\">\r\n      <ItemGroup>\r\n        <Reference Include=\"Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\" />\r\n      </ItemGroup>\r\n    </When>\r\n    <Otherwise>\r\n      <ItemGroup>\r\n        <Reference Include=\"Microsoft.VisualStudio.QualityTools.UnitTestFramework\">\r\n          <Private>False</Private>\r\n        </Reference>\r\n      </ItemGroup>\r\n    </Otherwise>\r\n  </Choose>\r\n  <ItemGroup>\r\n    <Compile Include=\"ApplicativeRewriteTest.cs\" />\r\n    <Compile Include=\"BindExpressionParseTest.cs\" />\r\n    <Compile Include=\"ExpressionTests.cs\" />\r\n    <Compile Include=\"MockData.cs\" />\r\n    <Compile Include=\"Blog.cs\" />\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\HaxlSharp.Core\\HaxlSharp.Core.csproj\">\r\n      <Project>{56487eb5-c699-4eaa-b384-c6f9e64635c5}</Project>\r\n      <Name>HaxlSharp.Core</Name>\r\n    </ProjectReference>\r\n    <ProjectReference Include=\"..\\HaxlSharp.Fetcher\\HaxlSharp.Fetcher.csproj\">\r\n      <Project>{4d87351f-eee6-4361-b889-d8217eb314aa}</Project>\r\n      <Name>HaxlSharp.Fetcher</Name>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <Choose>\r\n    <When Condition=\"'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'\">\r\n      <ItemGroup>\r\n        <Reference Include=\"Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\r\n          <Private>False</Private>\r\n        </Reference>\r\n        <Reference Include=\"Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\r\n          <Private>False</Private>\r\n        </Reference>\r\n        <Reference Include=\"Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\r\n          <Private>False</Private>\r\n        </Reference>\r\n        <Reference Include=\"Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\r\n          <Private>False</Private>\r\n        </Reference>\r\n      </ItemGroup>\r\n    </When>\r\n  </Choose>\r\n  <Import Project=\"$(VSToolsPath)\\TeamTest\\Microsoft.TestTools.targets\" Condition=\"Exists('$(VSToolsPath)\\TeamTest\\Microsoft.TestTools.targets')\" />\r\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\r\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r\n       Other similar extension points exist, see Microsoft.Common.targets.\r\n  <Target Name=\"BeforeBuild\">\r\n  </Target>\r\n  <Target Name=\"AfterBuild\">\r\n  </Target>\r\n  -->\r\n</Project>"
  },
  {
    "path": "HaxlSharp.Test/MockData.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace HaxlSharp.Test\r\n{\r\n    public class PostInfo\r\n    {\r\n        public readonly int PostId;\r\n        public readonly DateTime PostDate;\r\n        public readonly string PostTopic;\r\n        public readonly int AuthorId;\r\n        public PostInfo(int postId, DateTime postDate, string postTopic, int authorId)\r\n        {\r\n            PostId = postId;\r\n            PostDate = postDate;\r\n            PostTopic = postTopic;\r\n            AuthorId = authorId;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"PostInfo {{ Id: {PostId}, Date: {PostDate.ToShortDateString()}, Topic: '{PostTopic}'}}\";\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "HaxlSharp.Test/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\n\r\n// General Information about an assembly is controlled through the following \r\n// set of attributes. Change these attribute values to modify the information\r\n// associated with an assembly.\r\n[assembly: AssemblyTitle(\"HaxlSharp.Test\")]\r\n[assembly: AssemblyDescription(\"\")]\r\n[assembly: AssemblyConfiguration(\"\")]\r\n[assembly: AssemblyCompany(\"\")]\r\n[assembly: AssemblyProduct(\"HaxlSharp.Test\")]\r\n[assembly: AssemblyCopyright(\"Copyright ©  2016\")]\r\n[assembly: AssemblyTrademark(\"\")]\r\n[assembly: AssemblyCulture(\"\")]\r\n\r\n// Setting ComVisible to false makes the types in this assembly not visible \r\n// to COM components.  If you need to access a type in this assembly from \r\n// COM, set the ComVisible attribute to true on that type.\r\n[assembly: ComVisible(false)]\r\n\r\n// The following GUID is for the ID of the typelib if this project is exposed to COM\r\n[assembly: Guid(\"b62be199-4fab-41bf-bb52-a194e7e8106d\")]\r\n\r\n// Version information for an assembly consists of the following four values:\r\n//\r\n//      Major Version\r\n//      Minor Version \r\n//      Build Number\r\n//      Revision\r\n//\r\n// You can specify all the values or you can default the Build and Revision Numbers \r\n// by using the '*' as shown below:\r\n// [assembly: AssemblyVersion(\"1.0.*\")]\r\n[assembly: AssemblyVersion(\"0.1.*\")]\r\n"
  },
  {
    "path": "HaxlSharp.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio 2012\r\nVisualStudioVersion = 14.0.24720.0\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"HaxlSharp.Test\", \"HaxlSharp.Test\\HaxlSharp.Test.csproj\", \"{B62BE199-4FAB-41BF-BB52-A194E7E8106D}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"HaxlSharp.Core\", \"HaxlSharp.Core\\HaxlSharp.Core.csproj\", \"{56487EB5-C699-4EAA-B384-C6F9E64635C5}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"HaxlSharp.Fetcher\", \"HaxlSharp.Fetcher\\HaxlSharp.Fetcher.csproj\", \"{4D87351F-EEE6-4361-B889-D8217EB314AA}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{4D87351F-EEE6-4361-B889-D8217EB314AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{4D87351F-EEE6-4361-B889-D8217EB314AA}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{4D87351F-EEE6-4361-B889-D8217EB314AA}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{4D87351F-EEE6-4361-B889-D8217EB314AA}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{56487EB5-C699-4EAA-B384-C6F9E64635C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{56487EB5-C699-4EAA-B384-C6F9E64635C5}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{56487EB5-C699-4EAA-B384-C6F9E64635C5}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{56487EB5-C699-4EAA-B384-C6F9E64635C5}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{B62BE199-4FAB-41BF-BB52-A194E7E8106D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{B62BE199-4FAB-41BF-BB52-A194E7E8106D}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{B62BE199-4FAB-41BF-BB52-A194E7E8106D}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{B62BE199-4FAB-41BF-BB52-A194E7E8106D}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "LICENCE",
    "content": "MIT License\n\nCopyright (c) 2016 Joash Chong\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# HaxlSharp\nA C# implementation of [Haxl](https://github.com/facebook/Haxl) for composable data fetching with automatic concurrency and request deduplication. Not affiliated with Facebook in any way!\n\nTable of Contents\n=================\n\n  * [Quick start](#quick-start)\n  * [What's wrong with async/ await?](#whats-wrong-with-async-await)\n    * [Composing async methods](#composing-async-methods)\n    * [What's wrong with Task.WhenAll/ Promise.all?](#whats-wrong-with-taskwhenall-promiseall)\n  * [Haxl: reclaiming the sequential abstraction](#haxl-reclaiming-the-sequential-abstraction)\n    * [Composing requests](#composing-requests)\n    * [Request deduplication](#request-deduplication)\n  * [Implementation details](#implementation-details)\n  * [Integration](#integration)\n    * [Defining requests](#defining-requests)\n    * [Using the requests](#using-the-requests)\n    * [Handling requests](#handling-requests)\n    * [Implementing your own fetcher](#implementing-your-own-fetcher)\n      * [Why would you want to implement your own fetcher/ caching strategy?](#why-would-you-want-to-implement-your-own-fetcher-caching-strategy)\n      * [Fetcher](#fetcher)\n      * [Caching](#caching)\n  * [Limitations](#limitations)\n    * [Speed](#speed)\n    * [Anonymous types](#anonymous-types)\n    * [Applicative Do](#applicative-do)\n    * [It's a giant hack](#its-a-giant-hack)\n\n## Quick start \nInstall from nuget: [https://www.nuget.org/packages/HaxlSharp](https://www.nuget.org/packages/HaxlSharp)\n\nBefore you can use the library, you'll need to write a thin layer to get your existing data sources integrated with HaxlSharp- see the [Integration](#integration) section, or you can check out an example application using HaxlFetch [here](https://github.com/joashc/HaxlSharpDemo).\n\nOnce that's done, you can write your data fetches in a sequential way, and the framework will automatically perform requests as concurrently as possible, and do request deduplication.\n\n## What's wrong with async/ await?\nAsync/ await is great for writing sequential-looking code when you're only waiting for a single asynchronous request at a time, allowing us to write code without worrying about asynchronicity. But we often want to combine information from multiple data sources, like different calls on the same API, or multiple remote APIs.\n\nThe async/ await abstraction breaks down in these situations (and Javascript's async/await is no different). To illustrate, let's say we have a blogging site, and a post's metadata and content are retrieved using separate API calls. We could use async/ await to fetch both these pieces of information:\n\n```cs\npublic async Task<PostDetails> GetPostDetails(int postId)\n{\n    var postInfo = await FetchPostInfo(postId);\n    var postContent = await FetchPostContent(postId);\n    return new PostDetails(postInfo, postContent);\n}\n```\n\nHere, we're making two successive `await` calls, which means the execution will be suspended at the first request- `FetchPostInfo`- and only begin executing the second request- `FetchPostContent`- once the first request has completed.\n\nBut fetching `FetchPostContent` doesn't require the result of `FetchPostInfo`, which means we could have started both these requests concurrently! The \"correct\" way to write it is:\n\n```cs\nvar postInfoTask = FetchPostInfo(postId);\nvar postContentTask = FetchPostContent(postId);\nreturn new PostDetails(await postInfo, await postContent);\n```\n\nBut now we are dealing with tasks instead of their values; it's up to the programmer to ensure the task is `await`ed as late as possible. Async/ await is a good abstraction for *asynchronous* code, but writing *concurrent* code requires us to mix code that describes *what* we want to fetch with *how* we want to fetch it.\n\n### Composing async methods\nTo make matters worse, we can easily call our inefficient `GetPostDetails` method in a way that compounds the oversequentialization:\n\n```cs\npublic async Task<IEnumerable<PostDetails> LatestPostContent()\n{\n  var latest = await GetTwoLatestPostIds();\n  var first = await GetPostDetails(latest.Item1);\n  var second = await GetPostDetails(latest.Item2);\n  return new List<PostContent>{first, second};\n}\n```\n\nThis code will sequentially execute four calls that could have been executed concurrently! We should actually write our code like this:\n\n```cs\nvar latest = await GetTwoLatestPostIds();\nvar first = GetPostDetails(latest.Item1);\nvar second = GetPostDetails(latest.Item2);\nreturn new List<PostContent> { await first, await second };\n```\n\n### What's wrong with `Task.WhenAll`/ `Promise.all`?\nWe can manually add concurrency by giving up sequential-looking code that doesn't make a distinction between async values and \"normal\" values. In practice, this means dealing with both tasks and their `await`ed values, and sprinkling our code with `Task.WhenAll`.\n\nBut hang on, async/await was designed to solve these problems:\n\n- Writing asynchronous code is error-prone\n- Asynchronous code obscures the meaning of what we're trying to achieve\n- Programmers are bad at reasoning about asynchronous code\n\nGiving up our sequential abstraction means these exact problems have reemerged in the context of concurrency!\n\n- Writing **concurrent** code is error-prone\n- **Concurrent** code obscures the meaning of what we're trying to achieve\n- Programmers are bad at reasoning about **concurrent** code\n\n## Haxl: reclaiming the sequential abstraction\nHaxl allows us to write code that *looks* like it operates sequentially on \"normal values\", but is capable of being analyzed to determine the requests we can fetch concurrently, and then automatically batch these requests into a list.\n\nThis has a number of advantages over async/await and `Task.WhenAll`:\n\n- We can write code that uses the results of asynchronous requests, without the risk of losing concurrency.\n- Multiple requests to a single endpoint can be batched and handled more efficiently- for example, multiple concurrent requests to an SQL database could be rewritten into a single `SELECT` statement.\n- We only fetch duplicate requests once, even if the duplicate requests are started concurrently- something we can't achieve with `async` or `Task.WhenAll`.\n- Only fetching data once ensures data remains consistent within a request.\n\nTaken together, these advantages leave programmers free to compose complex data fetches, without worrying about concurrency or duplication. It also lessens the need to traverse large parts of the stack to write specialized data fetching methods. Only a small number of \"primitive requests\" need to be written across the stack; the rest can be composed from these primitives as necessary.\n\nLet's rewrite `GetPostDetails` using HaxlSharp:\n\n```cs\nFetch<PostDetails> GetPostDetails(int postId) =>\n    from info in FetchPostInfo(postId)\n    from content in FetchPostContent(postId)\n    select new PostDetails(info, content);\n```\n\nThe framework can automatically work out that these calls can be parallelized. Here's the debug log from when we fetch `GetPostDetails(1)`:\n\n```\n==== Batch ====\nFetched 'info': PostInfo { Id: 1, Date: 10/06/2016, Topic: 'Topic 1'}\nFetched 'content': Post 1\n\n==== Result ====\nPostDetails { Info: PostInfo { Id: 1, Date: 10/06/2016, Topic: 'Topic 1'}, Content: 'Post 1' }\n```\n\nBoth requests were automatically placed in a single batch and fetched concurrently!\n\n### Composing requests\nLet's compose our new `GetPostDetails` function:\n\n```cs\nFetch<List<PostDetails>> GetLatestPostDetails() =>\n  from latest in FetchTwoLatestPostIds()\n  // We must wait here\n  from first in GetPostDetails(latest.Item1)\n  from second in GetPostDetails(latest.Item2)\n  select new List<PostDetails> { first, second };\n```\n\nIf we fetch this, we get:\n\n```\n==== Batch ====\nFetched 'latest': (0, 1)\n\n==== Batch ====\nFetched 'content': Post 1\nFetched 'info': PostInfo { Id: 1, Date: 10/06/2016, Topic: 'Topic 1'}\nFetched 'content': Post 0\nFetched 'info': PostInfo { Id: 0, Date: 11/06/2016, Topic: 'Topic 0'}\n\n==== Result ====\n[ PostDetails { Info: PostInfo { Id: 0, Date: 11/06/2016, Topic: 'Topic 0'}, Content: 'Post 0' },\nPostDetails { Info: PostInfo { Id: 1, Date: 10/06/2016, Topic: 'Topic 1'}, Content: 'Post 1' } ]\n```\n\nThe framework has worked out that we have to wait for the first call's result before continuing, because we rely on this result to execute our subsequent calls. But the subsequent two calls only depend on `latest`, so once `latest` is fetched, they can both be fetched concurrently! \n\nNote that we made two parallelizable calls to `GetPostDetails`, which is itself made up of two parallelizable requests. These requests were \"pulled out\" and placed into a single batch of four concurrent requests. Let's see what happens if we rewrite `GetPostDetails` so that it must make two sequential requests:\n\n```cs\nFetch<PostDetails> GetPostDetails(int postId) =>\n    from info in FetchPostInfo(postId)\n    // We need to wait for the result of info before we can get this id!\n    from content in FetchPostContent(info.Id)\n    select new PostDetails(info, content);\n```\n\nnow when we fetch `GetLatestPostDetails`, we get:\n\n```\n==== Batch ====\nFetched 'latest': (0, 1)\n\n==== Batch ====\nFetched 'info': PostInfo { Id: 1, Date: 10/06/2016, Topic: 'Topic 1'}\nFetched 'info': PostInfo { Id: 0, Date: 11/06/2016, Topic: 'Topic 0'}\n\n==== Batch ====\nFetched 'content': Post 1\nFetched 'content': Post 0\n\n==== Result ====\n[ PostDetails { Info: PostInfo { Id: 0, Date: 11/06/2016, Topic: 'Topic 0'}, Content: 'Post 0' },\nPostDetails { Info: PostInfo { Id: 1, Date: 10/06/2016, Topic: 'Topic 1'}, Content: 'Post 1' } ]\n```\n\nThe `info` requests within `GetPostDetails` can be fetched with just the result of `latest`, so they were batched together. The remaining `content` batch can resume once the `info` batch completes.\n\n### Request deduplication\nBecause we lazily compose our requests, we can keep track of every subrequest within a particular request, and only fetch a particular subrequest once, even if they're part of the same batch.\n\nLet's say that each post has an author, and each author has three best friends. We could fetch the friends of the author of a given post like this:\n\n```cs\nFetch<IEnumerable<Person>> PostAuthorFriends(int postId) =>\n    from info in FetchPostInfo(postId)\n    from author in GetPerson(info.AuthorId)\n    from friends in author.BestFriendIds.SelectFetch(GetPerson)\n    select friends;\n```\n\nHere, we're using `SelectFetch`, which lets us run a request for every item in a list, and get back the list of results.  (`SelectFetch` has the signature `[a] -> (a -> Fetch a) -> Fetch [a]`- basically a monomorphic `sequenceA` to Haskellers).\n\nLet's fetch `PostAuthorFriends(3)`:\n\n```\n==== Batch ====\nFetched 'info': PostInfo { Id: 3, Date: 8/06/2016, Topic: 'Topic 0'}\n\n==== Batch ====\nFetched 'author': Person { PersonId: 19, Name: Johnie Wengerd, BestFriendIds: [ 10, 12, 14 ]  }\n\n==== Batch ====\nFetched 'friends[2]': Person { PersonId: 14, Name: Michal Zakrzewski, BestFriendIds: [ 5, 7, 9 ]  }\nFetched 'friends[0]': Person { PersonId: 10, Name: Shandra Hanlin, BestFriendIds: [ 13, 15, 17 ]  }\nFetched 'friends[1]': Person { PersonId: 12, Name: Peppa Pig, BestFriendIds: [ 19, 1, 3 ]  }\n\n==== Result ====\n[ Person { PersonId: 10, Name: Shandra Hanlin, BestFriendIds: [ 13, 15, 17 ]  },\n  Person { PersonId: 12, Name: Peppa Pig, BestFriendIds: [ 19, 1, 3 ]  },\n  Person { PersonId: 14, Name: Michal Zakrzewski, BestFriendIds: [ 5, 7, 9 ]  } ]\n```\n\nCalling `.SelectFetch(GetPerson)` on a list of three `PersonId`s gets us a list of three `Person` objects. Each item in the list was fetched in a single concurrent batch.\n\nNow let's see how we handle duplicate requests: \n\n```cs\nfrom ids in FetchTwoLatestPosts()\nfrom friends1 in PostAuthorFriends(ids.Item1)\nfrom friends2 in PostAuthorFriends(ids.Item2)\nselect friends1.Concat(friends2);\n```\n\nFetching this gives us:\n\n```\n==== Batch ====\nFetched 'ids': (3, 4)\n\n==== Batch ====\nFetched 'info': PostInfo { Id: 3, Date: 8/06/2016, Topic: 'Topic 0'}\nFetched 'info': PostInfo { Id: 4, Date: 7/06/2016, Topic: 'Topic 1'}\n\n==== Batch ====\nFetched 'author': Person { PersonId: 12, Name: Peppa Pig, BestFriendIds: [ 19, 1, 3 ]  }\nFetched 'author': Person { PersonId: 19, Name: Johnie Wengerd, BestFriendIds: [ 10, 12, 14 ]  }\n\n==== Batch ====\nFetched 'friends[0]': Person { PersonId: 10, Name: Shandra Hanlin, BestFriendIds: [ 13, 15, 17 ]  }\nFetched 'friends[2]': Person { PersonId: 3, Name: Corazon Benito, BestFriendIds: [ 2, 4, 6 ]  }\nFetched 'friends[1]': Person { PersonId: 1, Name: Cristal Hornak, BestFriendIds: [ 16, 18, 0 ]  }\nFetched 'friends[2]': Person { PersonId: 14, Name: Michal Zakrzewski, BestFriendIds: [ 5, 7, 9 ]  }\n\n==== Result ====\n[ Person { PersonId: 10, Name: Shandra Hanlin, BestFriendIds: [ 13, 15, 17 ]  },\n  Person { PersonId: 12, Name: Peppa Pig, BestFriendIds: [ 19, 1, 3 ]  },\n  Person { PersonId: 14, Name: Michal Zakrzewski, BestFriendIds: [ 5, 7, 9 ]  },\n  Person { PersonId: 1, Name: Cristal Hornak, BestFriendIds: [ 16, 18, 0 ]  },\n  Person { PersonId: 19, Name: Johnie Wengerd, BestFriendIds: [ 10, 12, 14 ]  },\n  Person { PersonId: 3, Name: Corazon Benito, BestFriendIds: [ 2, 4, 6 ]  } ]\n```\n\nBecause Peppa Pig and Johnie Wengerd are each other's best friends, we don't need to fetch them again when we're fetching their best friends. The fourth batch, where the best friends of Peppa and Johnie are fetched, only contains four requests, but the results are still correctly compiled into a list of six best friends.\n\nThis is also helpful for consistency; even though data can change during a fetch, we can still ensure that we don't get multiple versions of the same data within a single fetch.\n\n## Implementation details\nThe [original paper](http://community.haskell.org/~simonmar/papers/haxl-icfp14.pdf) gives a good overview of Haxl. Some differences between the C# and Haskell version are documented [here](http://joashc.github.io/posts/2016-06-11-haxlsharp.html).\n\n## Integration\nThe default API is similar to ServiceStack's, but it's straightforward to implement your own API if this one is not to your taste. You can implement your own API to HaxlSharp by just installing the `HaxlSharp.Core` package, instead of the `HaxlSharp` package, and implementing your own fetcher/ caching strategy. See [Implementing your own fetcher](#implementing-your-own-fetcher) for more details.\n\n### Defining requests\nYou can define requests with POCOs; just annotate their return type like so:\n\n```cs\npublic class FetchPostInfo : Returns<PostInfo>\n{\n    public readonly int PostId;\n    public FetchPostInfo(int postId)\n    {\n        PostId = postId;\n    }\n}\n```\n\n### Using the requests\nThis library operates on `Fetch<>` objects, so we write functions that create `Returns<>` objects and then call `ToFetch` on them:\n\n```cs\nFetch<PostInfo> GetPostInfo(int postId) => new GetPostInfo(postId).ToFetch();\nFetch<PostContent> GetPostContent(int postId) => new GetPostContent(postId).ToFetch();\n```\n\nNow we can compose any function that returns a `Fetch<>`, and they'll be automatically batched as much as possible:\n\n```cs\nFetch<PostDetails> GetPostDetails(int postId) =>\n    from info in GetPostInfo(postId)\n    from content in GetPostContent(postId)\n    select new PostDetails(info, content);\n\nFetch<IEnumerable<PostDetails>> RecentPostDetails() =>\n    from postIds in GetAllPostIds()\n    from postDetails in postIds.Take(10).SelectFetch(GetPostDetails)\n    select postDetails;\n```\n\n### Handling requests\nOf course, the data must come from somewhere, so we must create handlers for every request type. Handlers are just functions from the request type to the response type. Register these functions to create a `Fetcher` object:\n\n```cs\nvar fetcher = FetcherBuilder.New()\n  .FetchRequest<FetchPosts, IEnumerable<int>>(_ => _postApi.GetAllPostIds())\n  .FetchRequest<FetchPostInfo, PostInfo>(req => _postApi.GetPostInfo(req.PostId))\n  .FetchRequest<FetchUser, User>(req => _userApi.GetUser(req.UserId))\n  .Create();\n```\n\nThis object can be injected wherever you want to resolve a `Fetch<A>` into an `A`:\n\n```cs\nFetch<IEnumerable<string>> getPopularContent =\n    from postIds in GetAllPostIds()\n    from views in postIds.SelectFetch(GetPostViews)\n    from popularPosts in views.OrderByDescending(v => v.Views)\n                             .Take(5)\n                             .SelectFetch(v => GetPostContent(v.Id))\n    select popularPosts;\n\nIEnumerable<string> popularContent = await fetcher.Fetch(getPopularContent);\n```\n\nWe should work within the `Fetch<>` monad as much as possible, and only resolve the final `Fetch<>` when absolutely necessary. This ensures the framework performs the fetches in the most efficient way.\n\n### Implementing your own fetcher\nThis library comes with a default fetching and caching strategy, but it's possible to implement your own.\n\n#### Why would you want to implement your own fetcher/ caching strategy?\n\n- You think there's too much boilerplate with the default fetcher. The current implementation is optimized to make it easy to integrate with existing request objects, at the cost of slightly more boilerplate.\n- You don't want the overhead of serializing every request object to get a cache key, and/ or already have a way to create cache keys from your request objects.\n- You can do something clever with a batch of requests- you might bundle them up and send them to a particular server, for example.\n- You want to inject default values of failed requests\n\n#### Fetcher\nThe fetcher interface mainly requires you to implement: \n\n```cs\nTask FetchBatch(IEnumerable<BlockedRequest> requests);\n```\n\nA blocked request contains a request object and a `TaskCompletionSource`, which allows us to manually create and resolve `Task` objects- think Javascript promises. You'll want to map the list of blocked requests to a list of `Task`s, and manually resolve each one with the result of its respective request. \n\nThen you just return `Task.WhenAll` on the list of tasks!\n\n#### Caching\nTo customize the caching behaviour, you need  to implement a function that returns a cache key for a request:\n\n```cs\nstring ForRequest<A>(Returns<A> request);\n```\n\nNote that this is not traditional caching- it's intrarequest caching used for request deduplication and consistency. You'll still want to have a traditional caching layer.\n\n## Limitations\nThis library is still in its very early stages! Here is a very incomplete list of its limitations:\n\n### Speed\nThis is the most important one: it's still very unoptimized, so it adds an overhead that might not pay for itself!\n\nQueries written in the `Fetch` monad are actually treated as expression trees so they can be analysed to determine their dependencies. The expression trees are rewritten to maximise concurrency, and then compiled. Unfortunately, expression tree compilation is *slow* in C\\#!\n\nThis makes `SelectFetch` very inefficient on larger lists, because it compiles multiple expression trees for each item in the list. The Haskell version seems to have a similar asymptotic complexity, but with a *much* smaller constant.\n\n(Current plan for optimizing: instead of compiling an expression tree for each item in the list `[a]`, I could compile the expression `a -> Expression` once, and then plug `a` into this compiled expression. We'll see how this works out.)\n\n### Anonymous types\nIt's not recommended to return anonymous types from your `Fetch` functions, unless you want your functions to fail unpredictably. C\\# uses anonymous types internally for query expressions, which is alright in the case of [transparent identifiers](http://joashc.github.io/posts/2016-03-17-select-many-weird.html) because they're tagged with a special name only available to the compiler, but `let` statements are translated into plain old anonymous types that are indistinguishable from the ones you could type in manually:\n\n```cs\nfrom a in x\nfrom b in y\nselect new {a, b};\n```\n\nThere a few checks in place so anonymous types won't fail in all circumstances, but unless you want to memorize this list and ensure your expression doesn't meet all of these criteria:\n\n- Expression body is `ExpressionType.New`\n- Creates an anonymous type\n- Anonymous type has exactly two properties\n- First property of anonymous type is the same as the first parameter of the expression \n\n...you're better off just not using anonymous types.\n\n### Applicative Do\nWe're currently using a simplified version of the `ApplicativeDo` algorithm in GHC, so a query expression like:\n\n```cs\nfrom x in a\nfrom y in b(x)\nfrom z in c\n```\n\nis executed in three batches, even though `a` and `c` could be started concurrently.\n\n### It's a giant hack\nThe C# language spec goes to the effort of saying that the implementation details of query expression rewriting and scoping are *not* part of the specification, and different implementations of C# can do query rewriting/scoping differently.\n\nOf course, this library builds heavily on the internal, unspecified implementation details of query rewriting and scoping, so it's possible that the C\\# team could reimplement it and break the library.\n\nI think the C# team kept transparent identifiers, etc. out of the spec because they knew they were a bit of a hack to get the desired transitive scoping behaviour, which actually *is* part of the spec. So this library is a hack raised upon a hack... but it's called HaxlSharp, so at least the name is apt.\n"
  },
  {
    "path": "buildNuget.bat",
    "content": "move /Y nuget\\*.nupkg nuget\\previous\r\nnuget pack HaxlSharp.Core\\HaxlSharp.Core.csproj -Prop Configuration=Release -OutputDirectory nuget\\\r\nnuget pack HaxlSharp.Fetcher\\HaxlSharp.Fetcher.csproj -Prop Configuration=Release -IncludeReferencedProjects -OutputDirectory nuget\\\r\npause\r\n"
  }
]