Skip to content

Instantly share code, notes, and snippets.

@atifaziz
Last active September 20, 2020 08:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atifaziz/b166858fb3581f652846e73909e9b5ad to your computer and use it in GitHub Desktop.
Save atifaziz/b166858fb3581f652846e73909e9b5ad to your computer and use it in GitHub Desktop.
LINQPad helper for WebLINQ
<Query Kind="Program">
<NuGetReference Version="4.0.0">System.Reactive</NuGetReference>
<NuGetReference Version="4.5.0">System.Text.Encoding.CodePages</NuGetReference>
<NuGetReference Version="1.0.0-alpha-20200416" Prerelease="true">WebLinq</NuGetReference>
<Namespace>System.CodeDom.Compiler</Namespace>
<Namespace>System.Globalization</Namespace>
<Namespace>System.Net</Namespace>
<Namespace>System.Net.Http</Namespace>
<Namespace>System.Net.Http.Headers</Namespace>
<Namespace>System.Reactive</Namespace>
<Namespace>System.Reactive.Linq</Namespace>
<Namespace>System.Runtime.Versioning</Namespace>
<Namespace>System.Security.Cryptography</Namespace>
<Namespace>System.Web</Namespace>
<Namespace>WebLinq</Namespace>
<RemoveNamespace>System.Collections</RemoveNamespace>
<RemoveNamespace>System.Data</RemoveNamespace>
<RemoveNamespace>System.Linq.Expressions</RemoveNamespace>
<RemoveNamespace>System.Transactions</RemoveNamespace>
<RemoveNamespace>System.Xml</RemoveNamespace>
<RemoveNamespace>System.Xml.Linq</RemoveNamespace>
<RemoveNamespace>System.Xml.XPath</RemoveNamespace>
</Query>
DateTimeOffset QueryStartTime { get; set; }
[Conditional("LINQPAD")]
void DisableLoggingInLinqPad() => Logger.IsDisabled = true;
void OnInit()
{
if (GetType().Assembly.GetCustomAttribute<TargetFrameworkAttribute>() is TargetFrameworkAttribute fna)
{
Logger.Log("Target Framework = " + fna.FrameworkName);
if (Environment.GetEnvironmentVariable("DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER") == null
&& new FrameworkName(fna.FrameworkName).Version >= new Version(3, 0))
{
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
}
}
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
DisableLoggingInLinqPad();
}
void OnStart()
{
DisableLoggingInLinqPad();
var path =
#if LPLESS
Environment.GetEnvironmentVariable("LPLESS_LINQ_FILE_PATH")
#else
Util.CurrentQueryPath
#endif
;
var startTime = QueryStartTime = DateTimeOffset.Now;
Logger.Log($"{Path.GetFileNameWithoutExtension(path)} started at {startTime}.");
if (Assembly.GetExecutingAssembly().GetCustomAttribute<GeneratedCodeAttribute>() is GeneratedCodeAttribute gc)
Logger.Log($"Generator: {gc.Tool} ({gc.Version})");
}
void OnFinish()
{
var endTime = DateTimeOffset.Now;
Logger.Log($"Time taken was {endTime - QueryStartTime}.");
}
static void Print(string s)
{
using var _ = ConsoleLock.Enter();
Console.WriteLine(s);
}
[AttributeUsage(AttributeTargets.Method)]
sealed class QueryExpressionPrinterAttribute : Attribute {}
[QueryExpressionPrinter]
static void PrintQueryExpression<T>(IObservable<T> source) =>
PrintQueryExpression(source.ToEnumerable());
[QueryExpressionPrinter]
static void PrintQueryExpression<T>(IEnumerable<T> source)
{
var type = typeof(T);
if (type.IsPrimitive || Type.GetTypeCode(type) != TypeCode.Object)
{
Print(Enquote(type.Name));
foreach (var item in source.Select(Enquote))
Print(item);
}
else
{
var properties = Enumerable.ToArray(
from p in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where p.CanRead && p.GetIndexParameters().Length == 0
select new
{
Name = SnakeCaseFromPascal(p.Name),
GetValue = new Func<object, object>(p.GetValue),
});
if (!properties.Any())
throw new Exception(type + " objects have no properties.");
Print(string.Join(",", from p in properties select Enquote(p.Name)));
foreach (var item in source)
Print(string.Join(",", from p in properties select Enquote(p.GetValue(item))));
}
static string Enquote<TValue>(TValue value) =>
"\"" + Convert.ToString(value, CultureInfo.InvariantCulture).Replace("\"", "\"\"") + "\"";
static string SnakeCaseFromPascal(string s) =>
Regex.Replace(s, @"((?<![A-Z]|^)[A-Z]|(?<=[A-Z]+)[A-Z](?=[a-z]))", m => "_" + m.Value)
.ToLowerInvariant();
}
static readonly OptionalLock ConsoleLock = OptionalLock.FreeWhen(Console.IsOutputRedirected || Console.IsErrorRedirected);
sealed class OptionalLock
{
readonly object _lock;
readonly IDisposable _disposable;
static readonly OptionalLock Nil = new OptionalLock(null, Disposable.Nop);
public static OptionalLock Create() => When(true);
public static OptionalLock FreeWhen(bool disable) => When(!disable);
public static OptionalLock When(bool enable)
{
if (!enable)
return Nil;
var @lock = new object();
return new OptionalLock(@lock, new Disposable(() => Monitor.Exit(@lock)));
}
OptionalLock(object @lock, IDisposable disposable) =>
(_lock, _disposable) = (@lock, disposable);
public bool IsFree => _lock == null;
public IDisposable Enter()
{
if (_lock is object @lock)
Monitor.Enter(@lock);
return _disposable;
}
sealed class Disposable : IDisposable
{
public static readonly IDisposable Nop = new Disposable(null);
Action _delegatee;
public Disposable(Action delegatee) =>_delegatee = delegatee;
public void Dispose() => _delegatee?.Invoke();
}
}
public static class Logger
{
public static bool IsDisabled = false;
static readonly object Lock = new object();
public static void Log(string line, ConsoleColor backgroundColor = ConsoleColor.DarkGray,
ConsoleColor foregroundColor = ConsoleColor.White)
{
if (IsDisabled)
return;
using var _ = ConsoleLock.Enter();
lock (Lock)
{
ConsoleColor? oldBackgroundColor = default;
ConsoleColor? oldForegroundColor = default;
if (!Console.IsErrorRedirected)
{
oldBackgroundColor = Console.BackgroundColor;
Console.BackgroundColor = backgroundColor;
oldForegroundColor = Console.ForegroundColor;
Console.ForegroundColor = foregroundColor;
}
Console.Error.Write(line);
Console.Error.Flush();
if (oldBackgroundColor is ConsoleColor bc)
Console.BackgroundColor = bc;
if (oldForegroundColor is ConsoleColor fc)
Console.ForegroundColor = fc;
Console.Error.WriteLine();
}
}
}
static readonly IHttpClient Http =
WebLinq.HttpClient.Default
#if LPLESS
.Wrap(async (send, req, config) =>
{
Log(">", ConsoleColor.DarkCyan, $"{req.Method} {req.RequestUri}", req.Content?.Headers);
var rsp = await send(req, config);
Log("<", (int)rsp.StatusCode switch
{
var sc when sc >= 200 && sc < 400 => ConsoleColor.DarkGreen,
_ => ConsoleColor.DarkRed
},
$"{(int) rsp.StatusCode} ({rsp.StatusCode}) {rsp.ReasonPhrase}",
rsp.Content.Headers);
return rsp;
static void Log(string dir, ConsoleColor color, string epilogue, HttpContentHeaders headers)
{
var line =
$"{dir} HTTP {epilogue}"
+ (headers?.ContentType is MediaTypeHeaderValue h ? " (" + h + ")" : null)
+ (headers?.ContentLength is long len ? " [" + len + " bytes]" : null);
Logger.Log(line, color);
}
})
#endif
;
void Main() {}
<Query Kind="Program">
<NuGetReference Version="1.3.1">Dsv</NuGetReference>
<NuGetReference Version="4.0.0">System.Reactive</NuGetReference>
<NuGetReference Version="1.0.0-alpha-20200416" Prerelease="true">WebLinq</NuGetReference>
<Namespace>Dsv</Namespace>
<Namespace>System.Reactive.Linq</Namespace>
<Namespace>WebLinq</Namespace>
<Namespace>WebLinq.Text</Namespace>
<RemoveNamespace>System.Collections</RemoveNamespace>
<RemoveNamespace>System.Data</RemoveNamespace>
<RemoveNamespace>System.Diagnostics</RemoveNamespace>
<RemoveNamespace>System.IO</RemoveNamespace>
<RemoveNamespace>System.Linq</RemoveNamespace>
<RemoveNamespace>System.Linq.Expressions</RemoveNamespace>
<RemoveNamespace>System.Reflection</RemoveNamespace>
<RemoveNamespace>System.Threading</RemoveNamespace>
<RemoveNamespace>System.Transactions</RemoveNamespace>
<RemoveNamespace>System.Xml</RemoveNamespace>
<RemoveNamespace>System.Xml.Linq</RemoveNamespace>
<RemoveNamespace>System.Xml.XPath</RemoveNamespace>
</Query>
public sealed class DsvOptions
{
public static readonly DsvOptions CsvFormat = new DsvOptions(Format.Csv);
public static DsvOptions Delimiter(char ch) =>
CsvFormat.WithFormat(new Format(ch));
public Format Format { get; }
public Encoding Encoding { get; }
public Func<IEnumerable<string>, IEnumerable<string>> LinesFunction { get; }
public Func<string, bool> LineFilter { get; }
public DsvOptions(Format format) :
this(format, null, ls => ls, _ => false) {}
DsvOptions(Format format,
Encoding encoding,
Func<IEnumerable<string>, IEnumerable<string>> linesFunction,
Func<string, bool> lineFilter)
{
Format = format ?? throw new ArgumentNullException(nameof(format));
Encoding = encoding;
LinesFunction = linesFunction ?? throw new ArgumentNullException(nameof(linesFunction));
LineFilter = lineFilter ?? throw new ArgumentNullException(nameof(lineFilter));
}
public DsvOptions WithFormat(Format value) =>
value == Format ? this : new DsvOptions(value, Encoding, LinesFunction, LineFilter);
public DsvOptions WithEncoding(Encoding value) =>
value == Encoding ? this : new DsvOptions(Format, value, LinesFunction, LineFilter);
public DsvOptions WithLinesFunction(Func<IEnumerable<string>, IEnumerable<string>> value) =>
value == LinesFunction ? this : new DsvOptions(Format, Encoding, value, LineFilter);
public DsvOptions WithLineFilter(Func<string, bool> value) =>
value == LineFilter ? this : new DsvOptions(Format, Encoding, LinesFunction, value);
}
static partial class DsvExtensions
{
public static IObservable<HttpFetch<IEnumerable<(T Header, TextRow Row)>>>
Csv<T>(this IHttpObservable http,
Func<TextRow, T> headSelector) =>
http.Dsv(UserQuery.DsvOptions.CsvFormat, headSelector, ValueTuple.Create);
public static IObservable<HttpFetch<IEnumerable<TRow>>>
Csv<THead, TRow>(this IHttpObservable http,
Func<TextRow, THead> headSelector,
Func<THead, TextRow, TRow> rowSelector) =>
http.Dsv(UserQuery.DsvOptions.CsvFormat, headSelector, rowSelector);
public static IObservable<HttpFetch<IEnumerable<(T Header, TextRow Row)>>>
Dsv<T>(this IHttpObservable http,
UserQuery.DsvOptions options,
Func<TextRow, T> headSelector) =>
http.Dsv(options, headSelector, ValueTuple.Create);
public static IObservable<HttpFetch<IEnumerable<TRow>>>
Dsv<THead, TRow>(this IHttpObservable http,
UserQuery.DsvOptions options,
Func<TextRow, THead> headSelector,
Func<THead, TextRow, TRow> rowSelector) =>
from f in options.Encoding == null ? http.Text() : http.Text(options.Encoding)
select f.WithContent(options.LinesFunction(Regex.Split(f.Content.Trim(), @"\r?\n"))
.ParseDsv(options.Format, options.LineFilter, headSelector, rowSelector));
}
void Main() {}
<Query Kind="Program">
<NuGetReference Version="12.0.3">Newtonsoft.Json</NuGetReference>
<NuGetReference Version="4.0.0">System.Reactive</NuGetReference>
<NuGetReference Version="1.0.0-alpha-20190716T1343" Prerelease="true">WebLinq</NuGetReference>
<Namespace>Newtonsoft.Json</Namespace>
<Namespace>System.Reactive</Namespace>
<Namespace>System.Reactive.Linq</Namespace>
<Namespace>WebLinq</Namespace>
<RemoveNamespace>System.Collections</RemoveNamespace>
<RemoveNamespace>System.Collections.Generic</RemoveNamespace>
<RemoveNamespace>System.Data</RemoveNamespace>
<RemoveNamespace>System.Diagnostics</RemoveNamespace>
<RemoveNamespace>System.IO</RemoveNamespace>
<RemoveNamespace>System.Linq.Expressions</RemoveNamespace>
<RemoveNamespace>System.Reflection</RemoveNamespace>
<RemoveNamespace>System.Text.RegularExpressions</RemoveNamespace>
<RemoveNamespace>System.Threading</RemoveNamespace>
<RemoveNamespace>System.Transactions</RemoveNamespace>
<RemoveNamespace>System.Xml</RemoveNamespace>
<RemoveNamespace>System.Xml.Linq</RemoveNamespace>
<RemoveNamespace>System.Xml.XPath</RemoveNamespace>
</Query>
static partial class Json
{
public static string Stringify(object obj) =>
JsonConvert.SerializeObject(obj);
public static T Parse<T>(string json) =>
JsonConvert.DeserializeObject<T>(json);
public static T ParseAsPrototype<T>(string json, T prototype) =>
JsonConvert.DeserializeAnonymousType(json, prototype);
public static T ReinterpretAsPrototype<T>(object obj, T prototype) =>
Reinterpret<T>(obj);
public static T Reinterpret<T>(object obj)
{
var serializer = new JsonSerializer();
using var reader = Newtonsoft.Json.Linq.JToken.FromObject(obj).CreateReader();
return (T)serializer.Deserialize(reader, typeof(T));
}
}
static partial class JsonExtensions
{
public static IObservable<HttpFetch<T>> Json<T>(this IHttpObservable http, T prototype) =>
http.ReadContent(async f =>
JsonConvert.DeserializeAnonymousType(await f.Content.ReadAsStringAsync(), prototype));
public static IObservable<HttpFetch<T>> Json<T>(this IHttpObservable http, T prototype, Encoding encoding) =>
http.ReadContent(async f =>
{
var byteArray = await f.Content.ReadAsByteArrayAsync();
return JsonConvert.DeserializeAnonymousType(encoding.GetString(byteArray, 0, byteArray.Length), prototype);
});
public static IObservable<HttpFetch<T>> Json<T>(this IObservable<HttpFetch<string>> http, T prototype) =>
from fetch in http
select fetch.WithContent(JsonConvert.DeserializeAnonymousType(fetch.Content, prototype));
public static IObservable<T> DeserializeJson<T>(this IObservable<string> source, T prototype) =>
from json in source
select JsonConvert.DeserializeAnonymousType(json, prototype);
public static IObservable<HttpFetch<T>> Json<T>(this IHttpObservable http) =>
http.ReadContent(async f =>
JsonConvert.DeserializeObject<T>(await f.Content.ReadAsStringAsync()));
public static IObservable<HttpFetch<T>> Json<T>(this IHttpObservable http, Encoding encoding) =>
http.ReadContent(async f =>
{
var byteArray = await f.Content.ReadAsByteArrayAsync();
return JsonConvert.DeserializeObject<T>(encoding.GetString(byteArray, 0, byteArray.Length));
});
public static IObservable<HttpFetch<T>> Json<T>(this IObservable<HttpFetch<string>> http) =>
from fetch in http
select fetch.WithContent(JsonConvert.DeserializeObject<T>(fetch.Content));
public static IObservable<T> Json<T>(this IObservable<string> source, T prototype) =>
from json in source
select JsonConvert.DeserializeAnonymousType(json, prototype);
public static IObservable<T> Json<T>(this IObservable<string> source) =>
from json in source
select JsonConvert.DeserializeObject<T>(json);
}
void Main() {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment