diff --git a/.github/workflows/build_deploy_docs.yml b/.github/workflows/build_deploy_docs.yml index 2c5f3e41cd..6c826dd3f2 100644 --- a/.github/workflows/build_deploy_docs.yml +++ b/.github/workflows/build_deploy_docs.yml @@ -17,6 +17,7 @@ jobs: dotnet-version: | 5.0.x 6.0.x + 8.0.x - uses: actions/cache@v4 with: diff --git a/.github/workflows/code-gen.yml b/.github/workflows/code-gen.yml index 60d9aa7d7d..4fb265c3e5 100644 --- a/.github/workflows/code-gen.yml +++ b/.github/workflows/code-gen.yml @@ -16,11 +16,12 @@ jobs: uses: actions/checkout@v4 - name: Setup .NET SDK - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: | 5.0.x 6.0.x + 8.0.x - name: Cache Nuget Packages uses: actions/cache@v3 @@ -59,11 +60,12 @@ jobs: uses: actions/checkout@v4 - name: Setup .NET SDK - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: | 5.0.x 6.0.x + 8.0.x - name: Cache Nuget Packages uses: actions/cache@v3 diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 310b727142..623a5ce826 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -13,6 +13,7 @@ jobs: dotnet-version: | 5.0.x 6.0.x + 8.0.x - uses: actions/cache@v4 with: path: ~/.nuget/packages diff --git a/.github/workflows/integration-yaml-tests.yml b/.github/workflows/integration-yaml-tests.yml index 328ed2be71..adf927d8e5 100644 --- a/.github/workflows/integration-yaml-tests.yml +++ b/.github/workflows/integration-yaml-tests.yml @@ -35,6 +35,7 @@ jobs: dotnet-version: | 5.0.x 6.0.x + 8.0.x - uses: actions/cache@v4 with: @@ -96,6 +97,7 @@ jobs: dotnet-version: | 5.0.x 6.0.x + 8.0.x - uses: actions/cache@v4 with: diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 73ccb490ba..de9ff657ce 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -39,6 +39,7 @@ jobs: dotnet-version: | 5.0.x 6.0.x + 8.0.x - uses: actions/cache@v4 with: @@ -86,6 +87,7 @@ jobs: dotnet-version: | 5.0.x 6.0.x + 8.0.x - uses: actions/cache@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b80329215e..2d6397388f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,6 +13,7 @@ jobs: dotnet-version: | 5.0.x 6.0.x + 8.0.x - uses: actions/cache@v4 with: path: ~/.nuget/packages diff --git a/.github/workflows/test-jobs.yml b/.github/workflows/test-jobs.yml index 7a54dfde86..091624dd02 100644 --- a/.github/workflows/test-jobs.yml +++ b/.github/workflows/test-jobs.yml @@ -29,6 +29,7 @@ jobs: dotnet-version: | 5.0.x 6.0.x + 8.0.x - uses: actions/cache@v4 with: path: ~/.nuget/packages @@ -67,6 +68,7 @@ jobs: dotnet-version: | 5.0.x 6.0.x + 8.0.x - uses: actions/cache@v4 with: path: ~/.nuget/packages diff --git a/CHANGELOG.md b/CHANGELOG.md index 976de06afa..981c8171b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### Added - Added support for `MinScore` on `ScriptScoreQuery` ([#624](https://github.com/opensearch-project/opensearch-net/pull/624)) - Added support for the `Cat.PitSegments` and `Cat.SegmentReplication` APIs ([#527](https://github.com/opensearch-project/opensearch-net/pull/527)) +- Added support for serializing the `DateOnly` and `TimeOnly` types ([#734](https://github.com/opensearch-project/opensearch-net/pull/734)) ### Removed - Removed support for the `net461` target ([#256](https://github.com/opensearch-project/opensearch-net/pull/256)) @@ -198,4 +199,4 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) [1.6.0]: https://github.com/opensearch-project/opensearch-net/compare/v1.5.0...v1.6.0 [1.5.0]: https://github.com/opensearch-project/opensearch-net/compare/v1.4.0...v1.5.0 [1.4.0]: https://github.com/opensearch-project/opensearch-net/compare/v1.3.0...v1.4.0 -[1.3.0]: https://github.com/opensearch-project/opensearch-net/compare/v1.2.0...v1.3.0 \ No newline at end of file +[1.3.0]: https://github.com/opensearch-project/opensearch-net/compare/v1.2.0...v1.3.0 diff --git a/build/scripts/Targets.fs b/build/scripts/Targets.fs index 88ad03df88..44549305c0 100644 --- a/build/scripts/Targets.fs +++ b/build/scripts/Targets.fs @@ -38,16 +38,16 @@ open Fake.IO.Globbing.Operators module Main = - let private target name action = Targets.Target(name, Action(action)) + let private target name action = Targets.Target(name, Action(action)) let private skip name = printfn "SKIPPED target '%s' evaluated not to run" name |> ignore - let private conditional name optional action = target name (if optional then action else (fun _ -> skip name)) + let private conditional name optional action = target name (if optional then action else (fun _ -> skip name)) let private command name (dependencies: IEnumerable) action = Targets.Target(name, dependencies, Action(action)) - let private conditionalCommand name dependencies optional action = command name dependencies (if optional then action else (fun _ -> skip name)) - + let private conditionalCommand name dependencies optional action = command name dependencies (if optional then action else (fun _ -> skip name)) + /// Sets command line environments indicating we are building from the command line let setCommandLineEnvVars () = Environment.setEnvironVar"OSC_COMMAND_LINE_BUILD" "1" - + let sourceDir = Paths.TestsSource("Tests.Configuration"); let defaultYaml = Path.Combine(sourceDir, "tests.default.yaml"); let userYaml = Path.Combine(sourceDir, "tests.yaml"); @@ -56,59 +56,60 @@ module Main = | (true, _) -> Environment.setEnvironVar "OSC_YAML_FILE" (Path.GetFullPath(userYaml)) | (_, true) -> Environment.setEnvironVar "OSC_YAML_FILE" (Path.GetFullPath(defaultYaml)) | _ -> failwithf "Expected to find a tests.default.yaml or tests.yaml in %s" sourceDir - - - let [] main args = + + + let [] main args = async { do! Async.SwitchToThreadPool () - + setCommandLineEnvVars () - + let parsed = Commandline.parse (args |> Array.toList) - + let buildVersions = Versioning.BuildVersioning parsed let artifactsVersion = Versioning.ArtifactsVersion buildVersions Versioning.Validate parsed.Target buildVersions - + let isCanary = parsed.Target = "canary"; - + Tests.SetTestEnvironmentVariables parsed - + let testChain = ["clean"; "version"; "restore"; "full-build"; ] let buildChain = ["test"; "inherit-doc" ] let releaseChain = - [ + [ "build"; "nuget-pack"; - "nuget-pack-versioned"; + // "nuget-pack-versioned"; "validate-artifacts"; "generate-release-notes" ] let canaryChain = [ "version"; "release"; "test-nuget-package";] - - // the following are expected to be called as targets directly - conditional "clean" (parsed.ReleaseBuild || parsed.Target = "clean") <| fun _ -> Build.Clean parsed + + // the following are expected to be called as targets directly + conditional "clean" (parsed.ReleaseBuild || parsed.Target = "clean") <| fun _ -> Build.Clean parsed target "version" <| fun _ -> printfn "Artifacts Version: %O" artifactsVersion - - target "restore" Build.Restore + + target "restore" Build.Restore target "full-build" <| fun _ -> Build.Compile parsed artifactsVersion //TEST conditionalCommand "test" testChain (not parsed.SkipTests && not isCanary) <| fun _ -> Tests.RunUnitTests parsed target "inherit-doc" <| InheritDoc.PatchInheritDocs - + //BUILD command "build" buildChain <| fun _ -> printfn "STARTING BUILD" target "nuget-pack" <| fun _ -> Build.Pack artifactsVersion - conditional "nuget-pack-versioned" (isCanary) <| fun _ -> Build.VersionedPack artifactsVersion + // TODO: Re-enable once assembly-rewriter supports .NET 8.0 + // conditional "nuget-pack-versioned" (isCanary) <| fun _ -> Build.VersionedPack artifactsVersion conditional "generate-release-notes" (not isCanary) <| fun _ -> ReleaseNotes.GenerateNotes buildVersions - + target "validate-artifacts" <| fun _ -> Versioning.ValidateArtifacts artifactsVersion - + //RELEASE command "release" releaseChain <| fun _ -> let outputPath = match parsed.CommandArguments with | Commandline.SetVersion c -> c.OutputLocation | _ -> None @@ -124,18 +125,18 @@ module Main = printfn "Finished Release Build %O, output copied to: %s" artifactsVersion path conditional "test-nuget-package" (not parsed.SkipTests) <| fun _ -> Tests.RunReleaseUnitTests artifactsVersion parsed - + //CANARY command "canary" canaryChain <| fun _ -> printfn "Finished Release Build %O" artifactsVersion // ADDITIONAL COMMANDS - + command "cluster" [ "restore"; "full-build" ] <| fun _ -> ReposTooling.LaunchCluster parsed - + command "codegen" [ ] <| fun _ -> ReposTooling.GenerateApi parsed.RemainingArguments - + command "rest-spec-tests" [ ] <| fun _ -> ReposTooling.RestSpecTests parsed.RemainingArguments @@ -145,5 +146,5 @@ module Main = do! Targets.RunTargetsAndExitAsync([parsed.Target], (fun e -> e.GetType() = typeof)) |> Async.AwaitTask } |> Async.RunSynchronously - + 0 diff --git a/dotnet-tools.json b/dotnet-tools.json index c23a00d04d..13d7551c9b 100644 --- a/dotnet-tools.json +++ b/dotnet-tools.json @@ -3,28 +3,28 @@ "isRoot": true, "tools": { "assembly-rewriter": { - "version": "0.12.0", + "version": "0.13.0", "commands": [ "assembly-rewriter" ] }, "assembly-differ": { - "version": "0.13.0", + "version": "0.15.0", "commands": [ "assembly-differ" ] }, "nupkg-validator": { - "version": "0.4.0", + "version": "0.6.0", "commands": [ "nupkg-validator" ] }, "release-notes": { - "version": "0.3.1", + "version": "0.6.0", "commands": [ "release-notes" ] } } -} \ No newline at end of file +} diff --git a/global.json b/global.json index 650ed0fd4c..4efd4f0403 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.403", + "version": "8.0.107", "rollForward": "latestFeature", "allowPrerelease": false }, diff --git a/src/OpenSearch.Net/Configuration/RequestMetaData.cs b/src/OpenSearch.Net/Configuration/RequestMetaData.cs index a78e4a8b9b..39c4071f10 100644 --- a/src/OpenSearch.Net/Configuration/RequestMetaData.cs +++ b/src/OpenSearch.Net/Configuration/RequestMetaData.cs @@ -46,7 +46,7 @@ internal bool TryAddMetaData (string key, string value) { _metaDataItems ??= new Dictionary(); -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER return _metaDataItems.TryAdd(key, value); #else if (_metaDataItems.ContainsKey(key)) @@ -55,7 +55,7 @@ internal bool TryAddMetaData (string key, string value) _metaDataItems.Add(key, value); return true; #endif - } + } public IReadOnlyDictionary Items => _metaDataItems ?? EmptyReadOnly.Dictionary; } diff --git a/src/OpenSearch.Net/Connection/HandlerTracking/RequestDataHttpClientFactory.cs b/src/OpenSearch.Net/Connection/HandlerTracking/RequestDataHttpClientFactory.cs index ef3d3d853f..d44d55aee4 100644 --- a/src/OpenSearch.Net/Connection/HandlerTracking/RequestDataHttpClientFactory.cs +++ b/src/OpenSearch.Net/Connection/HandlerTracking/RequestDataHttpClientFactory.cs @@ -112,7 +112,7 @@ private HttpMessageHandler CreateHandler(int key, RequestData requestData) { if (requestData == null) throw new ArgumentNullException(nameof(requestData)); - #if NETSTANDARD2_1 + #if NETSTANDARD2_1 || NET6_0_OR_GREATER var entry = _activeHandlers.GetOrAdd(key, (k, r) => _entryFactory(k, r), requestData).Value; #else var entry = _activeHandlers.GetOrAdd(key, (k) => _entryFactory(k, requestData)).Value; diff --git a/src/OpenSearch.Net/Connection/MetaData/RuntimeVersionInfo.cs b/src/OpenSearch.Net/Connection/MetaData/RuntimeVersionInfo.cs index 0633eb3dce..135a8c1207 100644 --- a/src/OpenSearch.Net/Connection/MetaData/RuntimeVersionInfo.cs +++ b/src/OpenSearch.Net/Connection/MetaData/RuntimeVersionInfo.cs @@ -114,7 +114,11 @@ private static string GetNetCoreVersion() private static bool TryGetVersionFromAssemblyPath(Assembly assembly, out string runtimeVersion) { +#if NET6_0_OR_GREATER + var assemblyPath = assembly.Location.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries); +#else var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries); +#endif var netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App"); if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2) { diff --git a/src/OpenSearch.Net/ConnectionPool/SniffingConnectionPool.cs b/src/OpenSearch.Net/ConnectionPool/SniffingConnectionPool.cs index 20d5c09313..9073ffe5a9 100644 --- a/src/OpenSearch.Net/ConnectionPool/SniffingConnectionPool.cs +++ b/src/OpenSearch.Net/ConnectionPool/SniffingConnectionPool.cs @@ -81,7 +81,7 @@ public override void Reseed(IEnumerable nodes) { _readerWriter.EnterWriteLock(); var sortedNodes = SortNodes(nodesArray) - .DistinctBy(n => n.Uri) + .DistinctByInternal(n => n.Uri) .ToList(); InternalNodes = sortedNodes; diff --git a/src/OpenSearch.Net/ConnectionPool/StaticConnectionPool.cs b/src/OpenSearch.Net/ConnectionPool/StaticConnectionPool.cs index 3566a1f46d..12319671ad 100644 --- a/src/OpenSearch.Net/ConnectionPool/StaticConnectionPool.cs +++ b/src/OpenSearch.Net/ConnectionPool/StaticConnectionPool.cs @@ -82,7 +82,7 @@ private void Initialize(IEnumerable nodes, IDateTimeProvider dateTimeProvi } InternalNodes = SortNodes(nodesProvided) - .DistinctBy(n => n.Uri) + .DistinctByInternal(n => n.Uri) .ToList(); LastUpdate = DateTimeProvider.Now(); } diff --git a/src/OpenSearch.Net/Extensions/UtilExtensions.cs b/src/OpenSearch.Net/Extensions/UtilExtensions.cs index da699625ea..b6ca1645c1 100644 --- a/src/OpenSearch.Net/Extensions/UtilExtensions.cs +++ b/src/OpenSearch.Net/Extensions/UtilExtensions.cs @@ -90,7 +90,7 @@ internal static void ThrowIfNull(this T value, string name) where T : class internal static bool IsNullOrEmpty(this string value) => string.IsNullOrEmpty(value); - internal static IEnumerable DistinctBy(this IEnumerable items, Func property) => + internal static IEnumerable DistinctByInternal(this IEnumerable items, Func property) => items.GroupBy(property).Select(x => x.First()); internal static string ToTimeUnit(this TimeSpan timeSpan) diff --git a/src/OpenSearch.Net/OpenSearch.Net.csproj b/src/OpenSearch.Net/OpenSearch.Net.csproj index 38f9dd428b..155b16c0fd 100644 --- a/src/OpenSearch.Net/OpenSearch.Net.csproj +++ b/src/OpenSearch.Net/OpenSearch.Net.csproj @@ -13,12 +13,14 @@ true true - netstandard2.0;netstandard2.1 + netstandard2.0;netstandard2.1;net6.0;net8.0 true true + + diff --git a/src/OpenSearch.Net/Providers/RecyclableMemoryStream.cs b/src/OpenSearch.Net/Providers/RecyclableMemoryStream.cs index c7afe1aaae..0ef325882f 100644 --- a/src/OpenSearch.Net/Providers/RecyclableMemoryStream.cs +++ b/src/OpenSearch.Net/Providers/RecyclableMemoryStream.cs @@ -565,7 +565,7 @@ public int SafeRead(byte[] buffer, int offset, int count, ref int streamPosition return amountRead; } -#if NETCOREAPP2_1 || NETSTANDARD2_1 +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1 /// /// Reads from the current position into the provided buffer /// @@ -649,7 +649,7 @@ public override void Write(byte[] buffer, int offset, int count) _length = Math.Max(_position, _length); } -#if NETCOREAPP2_1 || NETSTANDARD2_1 +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1 /// /// Writes the buffer to the stream /// @@ -866,7 +866,7 @@ private int InternalRead(byte[] buffer, int offset, int count, int fromPosition) return amountToCopy; } -#if NETCOREAPP2_1 || NETSTANDARD2_1 +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1 private int InternalRead(Span buffer, int fromPosition) { if (_length - fromPosition <= 0) return 0; diff --git a/src/OpenSearch.Net/Providers/RecyclableMemoryStreamManager-Events.cs b/src/OpenSearch.Net/Providers/RecyclableMemoryStreamManager-Events.cs index f5088b23b0..89a5e97d79 100644 --- a/src/OpenSearch.Net/Providers/RecyclableMemoryStreamManager-Events.cs +++ b/src/OpenSearch.Net/Providers/RecyclableMemoryStreamManager-Events.cs @@ -56,7 +56,7 @@ namespace OpenSearch.Net { -#if !NETSTANDARD2_1 +#if !NETSTANDARD2_1 && !NET6_0_OR_GREATER internal class PollingCounter : IDisposable { // ReSharper disable UnusedParameter.Local diff --git a/src/OpenSearch.Net/Serialization/Formatters/ExceptionFormatter.cs b/src/OpenSearch.Net/Serialization/Formatters/ExceptionFormatter.cs index 03316469f2..acaf64f6b3 100644 --- a/src/OpenSearch.Net/Serialization/Formatters/ExceptionFormatter.cs +++ b/src/OpenSearch.Net/Serialization/Formatters/ExceptionFormatter.cs @@ -75,10 +75,21 @@ private static List> FlattenExceptions(Exception e) private static Dictionary ToDictionary(Exception e, int depth) { var o = new Dictionary(10); + +#if NET8_0_OR_GREATER + //NOTE: This is a workaround for the obsolete warning in .NET 8.0. We need to find a work around and remove this pragma +#pragma warning disable SYSLIB0050 // Type or member is obsolete var si = new SerializationInfo(e.GetType(), new FormatterConverter()); +#pragma warning restore SYSLIB0050 // Type or member is obsolete var sc = new StreamingContext(); +#pragma warning disable SYSLIB0051 // Type or member is obsolete e.GetObjectData(si, sc); - +#pragma warning restore SYSLIB0051 // Type or member is obsolete +#else + var si = new SerializationInfo(e.GetType(), new FormatterConverter()); + var sc = new StreamingContext(); + e.GetObjectData(si, sc); +#endif var helpUrl = si.GetString("HelpURL"); var stackTrace = si.GetString("StackTraceString"); var remoteStackTrace = si.GetString("RemoteStackTraceString"); diff --git a/src/OpenSearch.Net/Transport/PostData.cs b/src/OpenSearch.Net/Transport/PostData.cs index 037d33980a..1f62f537b7 100644 --- a/src/OpenSearch.Net/Transport/PostData.cs +++ b/src/OpenSearch.Net/Transport/PostData.cs @@ -46,7 +46,7 @@ public interface IPostData public enum PostType { ByteArray, -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER ReadOnlyMemory, #endif LiteralString, @@ -85,7 +85,7 @@ public abstract class PostData public static PostData Bytes(byte[] bytes) => new PostData(bytes); -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER public static PostData ReadOnlyMemory(ReadOnlyMemory bytes) => new PostData(bytes); #endif @@ -114,9 +114,9 @@ protected void FinishStream(Stream writableStream, MemoryStream buffer, IConnect } protected async -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER ValueTask - #else +#else Task #endif FinishStreamAsync(Stream writableStream, MemoryStream buffer, IConnectionConfigurationValues settings, CancellationToken ctx) @@ -135,7 +135,7 @@ public class PostData : PostData, IPostData private readonly IEnumerable _enumerableOfObject; private readonly IEnumerable _enumerableOfStrings; private readonly string _literalString; -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER private readonly ReadOnlyMemory _memoryOfBytes; #endif @@ -145,7 +145,7 @@ protected internal PostData(byte[] item) Type = PostType.ByteArray; } -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER protected internal PostData(ReadOnlyMemory item) { _memoryOfBytes = item; @@ -188,7 +188,7 @@ public override void Write(Stream writableStream, IConnectionConfigurationValues buffer = settings.MemoryStreamFactory.Create(WrittenBytes); break; -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER case PostType.ReadOnlyMemory: if (_memoryOfBytes.IsEmpty) return; @@ -281,7 +281,7 @@ public override async Task WriteAsync(Stream writableStream, IConnectionConfigur buffer = settings.MemoryStreamFactory.Create(WrittenBytes); break; -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER case PostType.ReadOnlyMemory: if (_memoryOfBytes.IsEmpty) return; diff --git a/src/OpenSearch.Net/Utf8Json/Formatters/DateTimeFormatter.cs b/src/OpenSearch.Net/Utf8Json/Formatters/DateTimeFormatter.cs index 534eaa9155..f746f58b1f 100644 --- a/src/OpenSearch.Net/Utf8Json/Formatters/DateTimeFormatter.cs +++ b/src/OpenSearch.Net/Utf8Json/Formatters/DateTimeFormatter.cs @@ -948,4 +948,51 @@ public TimeSpan Deserialize(ref JsonReader reader, IJsonFormatterResolver format throw new InvalidOperationException("invalid TimeSpan format. value:" + StringEncoding.UTF8.GetString(str.Array, str.Offset, str.Count)); } } + +#if NET6_0_OR_GREATER + internal sealed class DateOnlyFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new DateOnlyFormatter(); + + private readonly string _formatString; + + public DateOnlyFormatter() => _formatString = "o"; //we are choosing the ISO 8601 format as the default + + public DateOnlyFormatter(string formatString) => _formatString = formatString; + + public void Serialize(ref JsonWriter writer, DateOnly value, IJsonFormatterResolver formatterResolver) => + writer.WriteString(value.ToString(_formatString)); + + public DateOnly Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var str = reader.ReadString(); + return _formatString == null || _formatString == "o" + ? DateOnly.Parse(str, CultureInfo.InvariantCulture) + : DateOnly.ParseExact(str, _formatString, CultureInfo.InvariantCulture); + } + } + + internal sealed class TimeOnlyFormatter : IJsonFormatter + { + public static readonly IJsonFormatter Default = new TimeOnlyFormatter(); + + private readonly string _formatString; + + public TimeOnlyFormatter() => _formatString = "o"; //if we do not use o, you loose the milliseconds and microseconds + + public TimeOnlyFormatter(string formatString) => _formatString = formatString; + + public void Serialize(ref JsonWriter writer, TimeOnly value, IJsonFormatterResolver formatterResolver) => + writer.WriteString(value.ToString(_formatString)); + + public TimeOnly Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) + { + var str = reader.ReadString(); + return _formatString == null || _formatString == "o" + ? TimeOnly.Parse(str, CultureInfo.InvariantCulture) + : TimeOnly.ParseExact(str, _formatString, CultureInfo.InvariantCulture); + } + } +#endif + } diff --git a/src/OpenSearch.Net/Utf8Json/Formatters/StandardClassLibraryFormatters.cs b/src/OpenSearch.Net/Utf8Json/Formatters/StandardClassLibraryFormatters.cs index 821736b994..5e0fc3d4d5 100644 --- a/src/OpenSearch.Net/Utf8Json/Formatters/StandardClassLibraryFormatters.cs +++ b/src/OpenSearch.Net/Utf8Json/Formatters/StandardClassLibraryFormatters.cs @@ -610,7 +610,7 @@ public Task Deserialize(ref JsonReader reader, IJsonFormatterResolver formatt } } - #if NETSTANDARD2_1 + #if NETSTANDARD2_1 || NET6_0_OR_GREATER internal sealed class ValueTaskFormatter : IJsonFormatter> { public void Serialize(ref JsonWriter writer, ValueTask value, IJsonFormatterResolver formatterResolver) => diff --git a/src/OpenSearch.Net/Utf8Json/Formatters/ValueTupleFormatter.cs b/src/OpenSearch.Net/Utf8Json/Formatters/ValueTupleFormatter.cs index 4b1677292a..bf4f67e9c0 100644 --- a/src/OpenSearch.Net/Utf8Json/Formatters/ValueTupleFormatter.cs +++ b/src/OpenSearch.Net/Utf8Json/Formatters/ValueTupleFormatter.cs @@ -28,19 +28,19 @@ #region Utf8Json License https://github.com/neuecc/Utf8Json/blob/master/LICENSE // MIT License -// +// // Copyright (c) 2017 Yoshifumi Kawai -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -50,7 +50,7 @@ // SOFTWARE. #endregion -#if NETSTANDARD +#if NETSTANDARD || NET6_0_OR_GREATER using System; using OpenSearch.Net.Utf8Json.Internal; @@ -75,7 +75,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver if (reader.ReadIsNull()) throw new InvalidOperationException("Data is Nil, ValueTuple can not be null."); T1 item1 = default; - + var count = 0; reader.ReadIsBeginObjectWithVerify(); while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) @@ -93,7 +93,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResolver break; } } - + return new ValueTuple(item1); } } @@ -120,7 +120,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResol T1 item1 = default; T2 item2 = default; - + var count = 0; reader.ReadIsBeginObjectWithVerify(); while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) @@ -141,7 +141,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterResol break; } } - + return new ValueTuple(item1, item2); } } @@ -171,7 +171,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterR T1 item1 = default; T2 item2 = default; T3 item3 = default; - + var count = 0; reader.ReadIsBeginObjectWithVerify(); while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) @@ -195,7 +195,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFormatterR break; } } - + return new ValueTuple(item1, item2, item3); } } @@ -228,7 +228,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFormat T2 item2 = default; T3 item3 = default; T4 item4 = default; - + var count = 0; reader.ReadIsBeginObjectWithVerify(); while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) @@ -255,7 +255,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFormat break; } } - + return new ValueTuple(item1, item2, item3, item4); } } @@ -291,7 +291,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFo T3 item3 = default; T4 item4 = default; T5 item5 = default; - + var count = 0; reader.ReadIsBeginObjectWithVerify(); while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) @@ -321,7 +321,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJsonFo break; } } - + return new ValueTuple(item1, item2, item3, item4, item5); } } @@ -360,7 +360,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJs T4 item4 = default; T5 item5 = default; T6 item6 = default; - + var count = 0; reader.ReadIsBeginObjectWithVerify(); while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) @@ -393,7 +393,7 @@ public ValueTuple Deserialize(ref JsonReader reader, IJs break; } } - + return new ValueTuple(item1, item2, item3, item4, item5, item6); } } @@ -435,7 +435,7 @@ public ValueTuple Deserialize(ref JsonReader reader, T5 item5 = default; T6 item6 = default; T7 item7 = default; - + var count = 0; reader.ReadIsBeginObjectWithVerify(); while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) @@ -471,7 +471,7 @@ public ValueTuple Deserialize(ref JsonReader reader, break; } } - + return new ValueTuple(item1, item2, item3, item4, item5, item6, item7); } } @@ -516,7 +516,7 @@ public ValueTuple Deserialize(ref JsonReader T6 item6 = default; T7 item7 = default; TRest item8 = default; - + var count = 0; reader.ReadIsBeginObjectWithVerify(); while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) @@ -555,7 +555,7 @@ public ValueTuple Deserialize(ref JsonReader break; } } - + return new ValueTuple(item1, item2, item3, item4, item5, item6, item7, item8); } } diff --git a/src/OpenSearch.Net/Utf8Json/Formatters/ValueTupleFormatter.tt b/src/OpenSearch.Net/Utf8Json/Formatters/ValueTupleFormatter.tt index 7fa8106fb0..6a14a0bbd7 100644 --- a/src/OpenSearch.Net/Utf8Json/Formatters/ValueTupleFormatter.tt +++ b/src/OpenSearch.Net/Utf8Json/Formatters/ValueTupleFormatter.tt @@ -1,4 +1,4 @@ -<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ output extension=".cs" #> @@ -7,7 +7,8 @@ * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. -* +*/ +/* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. * @@ -31,19 +32,19 @@ #region Utf8Json License https://github.com/neuecc/Utf8Json/blob/master/LICENSE // MIT License -// +// // Copyright (c) 2017 Yoshifumi Kawai -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -53,17 +54,17 @@ // SOFTWARE. #endregion -#if NETSTANDARD +#if NETSTANDARD || NET6_0_OR_GREATER using System; using OpenSearch.Net.Utf8Json.Internal; namespace OpenSearch.Net.Utf8Json.Formatters { -<# for(var i = 1; i <= 8; i++) { +<# for(var i = 1; i <= 8; i++) { Func toT = x => "T" + ((x == 8) ? "Rest" : x.ToString()); Func toItem = x => ((x == 8) ? "Rest" : "Item" + x); - var ts = string.Join(", ", Enumerable.Range(1, i).Select(x => toT(x))); - var t = "ValueTuple<" + ts + ">"; + var ts = string.Join(", ", Enumerable.Range(1, i).Select(x => toT(x))); + var t = "ValueTuple<" + ts + ">"; #> internal sealed class ValueTupleFormatter<<#= ts #>> : IJsonFormatter<<#= t #>><#= (t.Contains("TRest") ? " where TRest : struct" : "") #> { @@ -88,7 +89,7 @@ namespace OpenSearch.Net.Utf8Json.Formatters <# for(var j = 1; j <= i; j++) { #> <#= toT(j) #> item<#= j #> = default; <# } #> - + var count = 0; reader.ReadIsBeginObjectWithVerify(); while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) @@ -108,7 +109,7 @@ namespace OpenSearch.Net.Utf8Json.Formatters break; } } - + return new ValueTuple<<#= ts #>>(<#= string.Join(", ", Enumerable.Range(1, i).Select(x => "item" + x)) #>); } } diff --git a/src/OpenSearch.Net/Utf8Json/Resolvers/BuiltinResolver.cs b/src/OpenSearch.Net/Utf8Json/Resolvers/BuiltinResolver.cs index 5d79a7eb36..bf1b682205 100644 --- a/src/OpenSearch.Net/Utf8Json/Resolvers/BuiltinResolver.cs +++ b/src/OpenSearch.Net/Utf8Json/Resolvers/BuiltinResolver.cs @@ -121,6 +121,13 @@ internal static class BuiltinResolverGetFormatterHelper {typeof(TimeSpan?), new StaticNullableFormatter(ISO8601TimeSpanFormatter.Default)}, {typeof(DateTimeOffset?),new StaticNullableFormatter(ISO8601DateTimeOffsetFormatter.Default)}, +#if NET6_0_OR_GREATER + {typeof(DateOnly), DateOnlyFormatter.Default}, + {typeof(TimeOnly), TimeOnlyFormatter.Default}, + {typeof(DateOnly?), new StaticNullableFormatter(DateOnlyFormatter.Default)}, + {typeof(TimeOnly?), new StaticNullableFormatter(TimeOnlyFormatter.Default)}, +#endif + {typeof(string), NullableStringFormatter.Default}, {typeof(char), CharFormatter.Default}, {typeof(char?), NullableCharFormatter.Default}, diff --git a/src/OpenSearch.Net/Utf8Json/Resolvers/DynamicGenericResolver.cs b/src/OpenSearch.Net/Utf8Json/Resolvers/DynamicGenericResolver.cs index 819a382f57..486ccbc84f 100644 --- a/src/OpenSearch.Net/Utf8Json/Resolvers/DynamicGenericResolver.cs +++ b/src/OpenSearch.Net/Utf8Json/Resolvers/DynamicGenericResolver.cs @@ -150,7 +150,7 @@ internal static object GetFormatter(Type t) if (isNullable && nullableElementType.IsConstructedGenericType && nullableElementType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType }); -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER // ValueTask if (genericType == typeof(ValueTask<>)) return CreateInstance(typeof(ValueTaskFormatter<>), t.GenericTypeArguments); @@ -196,7 +196,7 @@ internal static object GetFormatter(Type t) return CreateInstance(tupleFormatterType, t.GenericTypeArguments); } -#if NETSTANDARD +#if NETSTANDARD || NET6_0_OR_GREATER // ValueTuple if (t.FullName.StartsWith("System.ValueTuple")) { diff --git a/src/OpenSearch.Net/Utf8Json/Resolvers/DynamicObjectResolver.cs b/src/OpenSearch.Net/Utf8Json/Resolvers/DynamicObjectResolver.cs index 3a0a0dda17..4683ee901e 100644 --- a/src/OpenSearch.Net/Utf8Json/Resolvers/DynamicObjectResolver.cs +++ b/src/OpenSearch.Net/Utf8Json/Resolvers/DynamicObjectResolver.cs @@ -301,8 +301,8 @@ private static TypeInfo BuildType(DynamicAssembly assembly, Type type, Func { - FieldInfo fi; - if (!customFormatterLookup.TryGetValue(member, out fi)) return false; + if (!customFormatterLookup.TryGetValue(member, out var fi)) + return false; il.EmitLoadThis(); il.EmitLdfld(fi); @@ -318,8 +318,8 @@ private static TypeInfo BuildType(DynamicAssembly assembly, Type type, Func { - FieldInfo fi; - if (!customFormatterLookup.TryGetValue(member, out fi)) return false; + if (!customFormatterLookup.TryGetValue(member, out var fi)) + return false; il.EmitLoadThis(); il.EmitLdfld(fi); @@ -343,10 +343,12 @@ public static object BuildAnonymousFormatter(Type type, Func nam }.Select(x => nameMutator(x))); // special case for exception, modify - serializationInfo = new MetaType(type, nameMutator, propertyMapper, false); + serializationInfo = new MetaType(type, nameMutator, propertyMapper, false) + { + BestMatchConstructor = null, + ConstructorParameters = [] + }; - serializationInfo.BestMatchConstructor = null; - serializationInfo.ConstructorParameters = new MetaMember[0]; serializationInfo.Members = new[] { new StringConstantValueMetaMember(nameMutator("ClassName"), type.FullName) } .Concat(serializationInfo.Members.Where(x => !ignoreSet.Contains(x.Name))) .Concat(new[] { new InnerExceptionMetaMember(nameMutator("InnerException")) }) @@ -1256,7 +1258,12 @@ internal static class EmitInfo public static readonly MethodInfo GetCustomAttributeJsonFormatterAttribute = ExpressionUtility.GetMethodInfo(() => CustomAttributeExtensions.GetCustomAttribute(default(MemberInfo), default(bool))); public static readonly MethodInfo ActivatorCreateInstance = ExpressionUtility.GetMethodInfo(() => Activator.CreateInstance(default(Type), default(object[]))); + +#if NET5_0_OR_GREATER + public static readonly MethodInfo GetUninitializedObject = ExpressionUtility.GetMethodInfo(() => System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject(default(Type))); +#else public static readonly MethodInfo GetUninitializedObject = ExpressionUtility.GetMethodInfo(() => System.Runtime.Serialization.FormatterServices.GetUninitializedObject(default(Type))); +#endif public static readonly MethodInfo GetTypeMethod = ExpressionUtility.GetMethodInfo((object o) => o.GetType()); public static readonly MethodInfo TypeGetGenericArguments = ExpressionUtility.GetPropertyInfo((Type t) => t.GenericTypeArguments).GetMethod; diff --git a/tests/Tests.YamlRunner/AsyncExtensions.fs b/tests/Tests.YamlRunner/AsyncExtensions.fs index 7316bbbe4e..837e7b447e 100644 --- a/tests/Tests.YamlRunner/AsyncExtensions.fs +++ b/tests/Tests.YamlRunner/AsyncExtensions.fs @@ -35,27 +35,27 @@ open System.Runtime.ExceptionServices [] [] -module AsyncExtensions = - type Microsoft.FSharp.Control.Async with - - // Wrote this as Async.Parallel eagerly materializes and forcefully executes in order. - // There is an extension that came in as dependency that extends Async.Parallel with maxDegreeOfParallelism - // but for some reason this did not behave as I had expected - [] - static member inline ForEachAsync (maxDegreeOfParallelism: int) asyncs = async { - let tasks = List>(maxDegreeOfParallelism) - let results = List<'a>() - for async in asyncs do - let! x = Async.StartChildAsTask async - tasks.Add <| x - if (tasks.Count >= maxDegreeOfParallelism) then - let! task = Async.AwaitTask <| Task.WhenAny(tasks) - if (task.IsFaulted) then ExceptionDispatchInfo.Capture(task.Exception).Throw(); - results.Add(task.Result) - let _ = tasks.Remove <| task - ignore() - - let! completed = Async.AwaitTask <| Task.WhenAll tasks - for c in completed do results.Add c - return results |> Seq.toList - } +module AsyncExtensions = + type Microsoft.FSharp.Control.Async with + + // Wrote this as Async.Parallel eagerly materializes and forcefully executes in order. + // There is an extension that came in as dependency that extends Async.Parallel with maxDegreeOfParallelism + // but for some reason this did not behave as I had expected + [] + static member inline ForEachAsync (maxDegreeOfParallelism: int) asyncs = async { + let tasks = List>(maxDegreeOfParallelism) + let results = List<'a>() + for async in asyncs do + let! x = Async.StartChildAsTask async + tasks.Add <| x + if (tasks.Count >= maxDegreeOfParallelism) then + let! task = Async.AwaitTask <| Task.WhenAny(tasks) + if (task.IsFaulted) then ExceptionDispatchInfo.Capture(task.Exception).Throw(); + results.Add(task.Result) + let _ = tasks.Remove <| task + ignore() + + let! completed = Async.AwaitTask <| Task.WhenAll tasks + for c in completed do results.Add c + return results |> Seq.toList + } diff --git a/tests/Tests/ClientConcepts/LowLevel/PostData.doc.cs b/tests/Tests/ClientConcepts/LowLevel/PostData.doc.cs index f42fa65b4a..b357d653f2 100644 --- a/tests/Tests/ClientConcepts/LowLevel/PostData.doc.cs +++ b/tests/Tests/ClientConcepts/LowLevel/PostData.doc.cs @@ -26,6 +26,9 @@ * under the License. */ +#pragma warning disable IDE1006 // Naming Styles +#pragma warning disable IDE0044 // Add readonly modifier + using System; using System.Collections.Generic; using System.IO; @@ -64,12 +67,12 @@ public class PostingData public PostingData() { - this.@object = new { my_object = "value" }; - this.collectionOfObjects = Enumerable.Range(0, 5).Select(i => @object).Cast().ToList(); + @object = new { my_object = "value" }; + collectionOfObjects = Enumerable.Range(0, 5).Select(i => @object).Cast().ToList(); var json = "{\"my_object\":\"value\"}"; - this.utf8ObjectBytes = Utf8Bytes(json); - this.utf8BytesOfListOfStrings = Utf8Bytes(string.Join("\n", collectionOfStrings) + "\n"); - this.utf8BytesOfCollectionOfObjects = Utf8Bytes(string.Join("\n", collectionOfObjects.Select(o=> json)) + "\n"); + utf8ObjectBytes = Utf8Bytes(json); + utf8BytesOfListOfStrings = Utf8Bytes(string.Join("\n", collectionOfStrings) + "\n"); + utf8BytesOfCollectionOfObjects = Utf8Bytes(string.Join("\n", collectionOfObjects.Select(o=> json)) + "\n"); } [U] public void ImplicitConversions() @@ -118,9 +121,9 @@ [U] public void ExplicitCreation() * Let's demonstrate how to use the static helper on `PostData` for these: */ - PostData fromObject = PostData.Serializable(@object); - PostData fromListOfString = PostData.MultiJson(collectionOfStrings); - PostData fromListOfObject = PostData.MultiJson(collectionOfObjects); + var fromObject = PostData.Serializable(@object); + var fromListOfString = PostData.MultiJson(collectionOfStrings); + var fromListOfObject = PostData.MultiJson(collectionOfObjects); /** The `Type` property is representative of the original type from which post data is constructed */ fromListOfString.Type.Should().Be(PostType.EnumerableOfString); @@ -139,8 +142,8 @@ [U] public void ExplicitCreation() //hide [U] public async Task WritesCorrectlyUsingBothLowAndHighLevelSettings() { - await this.AssertOn(new ConnectionSettings()); - await this.AssertOn(new ConnectionConfiguration()); + await AssertOn(new ConnectionSettings()); + await AssertOn(new ConnectionConfiguration()); } private async Task AssertOn(IConnectionConfigurationValues settings) @@ -260,3 +263,5 @@ private static async Task PostAssertAsync(PostData postData, byte[] writes, bool } } +#pragma warning restore IDE0044 // Add readonly modifier +#pragma warning restore IDE1006 // Naming Styles diff --git a/tests/Tests/CodeStandards/NamingConventions.doc.cs b/tests/Tests/CodeStandards/NamingConventions.doc.cs index 8e877c204a..7cfc52ceb5 100644 --- a/tests/Tests/CodeStandards/NamingConventions.doc.cs +++ b/tests/Tests/CodeStandards/NamingConventions.doc.cs @@ -197,6 +197,7 @@ public void AllOscTypesAreInOscNamespace() oscAssembly.GetType("System.ComponentModel.Browsable", throwOnError: false), oscAssembly.GetType("Microsoft.CodeAnalysis.EmbeddedAttribute", throwOnError: false), oscAssembly.GetType("System.Runtime.CompilerServices.IsReadOnlyAttribute", throwOnError: false), + oscAssembly.GetType("System.Runtime.CompilerServices.RefSafetyRulesAttribute", throwOnError: false) }; var types = oscAssembly.GetTypes(); @@ -233,7 +234,10 @@ public void AllOpenSearchNetTypesAreInOpenSearchNetNamespace() opensearchNetAssembly.GetType("Purify.Purifier+PurifierDotNet"), opensearchNetAssembly.GetType("Purify.Purifier+PurifierMono"), opensearchNetAssembly.GetType("Purify.Purifier+UriInfo"), - opensearchNetAssembly.GetType("System.ComponentModel.Browsable") + opensearchNetAssembly.GetType("System.ComponentModel.Browsable"), + opensearchNetAssembly.GetType("System.Runtime.CompilerServices.NullableAttribute"), + opensearchNetAssembly.GetType("System.Runtime.CompilerServices.NullableContextAttribute"), + opensearchNetAssembly.GetType("System.Runtime.CompilerServices.RefSafetyRulesAttribute") }; var types = opensearchNetAssembly.GetTypes();