{"action":"created","comment":{"url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/comments/240841669","pull_request_review_id":183965409,"id":240841669,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI0MDg0MTY2OQ==","diff_hunk":"@@ -0,0 +1,408 @@\n+using System;\n+using System.Collections;\n+using System.Collections.Generic;\n+using System.Linq;\n+using System.Linq.Expressions;\n+using System.Reflection;\n+using JetBrains.Annotations;\n+using Microsoft.EntityFrameworkCore;\n+using Microsoft.EntityFrameworkCore.Query.Expressions;\n+using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators;\n+using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Expressions.Internal;\n+\n+namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Internal\n+{\n+    /// <summary>\n+    /// Provides translation services for PostgreSQL array operators mapped to methods declared on\n+    /// <see cref=\"Array\"/>, <see cref=\"Enumerable\"/>, <see cref=\"List{T}\"/>, and <see cref=\"NpgsqlArrayExtensions\"/>.\n+    /// </summary>\n+    /// <remarks>\n+    /// See: https://www.postgresql.org/docs/current/static/functions-array.html\n+    /// </remarks>\n+    public class NpgsqlArrayMethodCallTranslator : IMethodCallTranslator\n+    {\n+        /// <summary>\n+        /// The backend version to target.\n+        /// </summary>\n+        [CanBeNull] readonly Version _postgresVersion;\n+\n+        /// <summary>\n+        /// Initializes a new instance of the <see cref=\"NpgsqlArrayMethodCallTranslator\"/> class.\n+        /// </summary>\n+        /// <param name=\"postgresVersion\">The backend version to target.</param>\n+        public NpgsqlArrayMethodCallTranslator([CanBeNull] Version postgresVersion) => _postgresVersion = postgresVersion;\n+\n+        /// <inheritdoc />\n+        [CanBeNull]\n+        public Expression Translate(MethodCallExpression expression)\n+            => EnumerableHandler(expression) ??\n+               NpgsqlArrayExtensionsHandler(expression) ??\n+               ArrayStaticHandler(expression) ??\n+               ArrayInstanceHandler(expression) ??\n+               StringInstanceHandler(expression) ??\n+               ListInstanceHandler(expression);\n+\n+        #region Handlers\n+\n+        /// <summary>\n+        /// Translates methods defined on <see cref=\"Enumerable\"/>.\n+        /// </summary>\n+        /// <param name=\"expression\">The expression to translate.</param>\n+        /// <returns>\n+        /// A translated expression or null if no translation is supported.\n+        /// </returns>\n+        [CanBeNull]\n+        Expression EnumerableHandler([NotNull] MethodCallExpression expression)\n+        {\n+            if (expression.Method.DeclaringType != typeof(Enumerable))\n+                return null;\n+\n+            var type = expression.Arguments[0].Type;\n+\n+            if (!type.IsArray && type != typeof(string) && (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(List<>)))\n+                return null;\n+\n+            if (!VersionAtLeast(7, 4))\n+                return null;\n+\n+            switch (expression.Method.Name)\n+            {\n+            case nameof(Enumerable.Count) when type == typeof(string):\n+                return\n+                    Expression.Coalesce(\n+                        new SqlFunctionExpression(\n+                            \"character_length\",\n+                            typeof(int?),\n+                            new[] { expression.Arguments[0] }),\n+                        Expression.Constant(0));\n+\n+            case nameof(Enumerable.Count):\n+                return VersionAtLeast(8, 4)\n+                    ? Expression.Coalesce(\n+                        new SqlFunctionExpression(\n+                            \"array_length\",\n+                            typeof(int?),\n+                            new[] { expression.Arguments[0], Expression.Constant(1) }),\n+                        Expression.Constant(0))\n+                    : null;\n+\n+            case nameof(Enumerable.ElementAt):\n+                return MakeIndex(expression.Arguments[0], expression.Arguments[1]);\n+\n+            case nameof(Enumerable.Append):\n+                return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], \"||\", expression.Arguments[0].Type);\n+\n+            case nameof(Enumerable.Prepend):\n+                return new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[0], \"||\", expression.Arguments[0].Type);\n+\n+            case nameof(Enumerable.SequenceEqual):\n+                return Expression.MakeBinary(ExpressionType.Equal, expression.Arguments[0], expression.Arguments[1]);\n+\n+            default:\n+                return null;\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Translates methods defined on <see cref=\"NpgsqlArrayExtensions\"/>.\n+        /// </summary>\n+        /// <param name=\"expression\">The expression to translate.</param>\n+        /// <returns>\n+        /// A translated expression or null if no translation is supported.\n+        /// </returns>\n+        /// <remarks>\n+        /// This handler throws on unsupported versions since <see cref=\"NpgsqlArrayExtensions\"/>\n+        /// does not support client-side evaluation.\n+        /// </remarks>\n+        [CanBeNull]\n+        Expression NpgsqlArrayExtensionsHandler([NotNull] MethodCallExpression expression)\n+        {\n+            if (expression.Method.DeclaringType != typeof(NpgsqlArrayExtensions))\n+                return null;\n+\n+            switch (expression.Method.Name)\n+            {\n+            case nameof(NpgsqlArrayExtensions.Contains):\n+                return VersionAtLeast(8, 2)\n+                    ? new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], \"@>\", typeof(bool))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.Contains), 8, 2);\n+\n+            case nameof(NpgsqlArrayExtensions.ContainedBy):\n+                return VersionAtLeast(8, 2)\n+                    ? new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], \"<@\", typeof(bool))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.ContainedBy), 8, 2);\n+\n+            case nameof(NpgsqlArrayExtensions.Overlaps):\n+                return VersionAtLeast(8, 2)\n+                    ? new CustomBinaryExpression(expression.Arguments[1], expression.Arguments[2], \"&&\", typeof(bool))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.Overlaps), 8, 2);\n+\n+            case nameof(NpgsqlArrayExtensions.ArrayFill):\n+                return VersionAtLeast(8, 4)\n+                    ? new SqlFunctionExpression(\"array_fill\", expression.Method.ReturnType, expression.Arguments.Skip(1))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.ArrayFill), 8, 4);\n+\n+            case nameof(NpgsqlArrayExtensions.ListFill):\n+                return VersionAtLeast(8, 4)\n+                    ? new SqlFunctionExpression(\"array_fill\", expression.Method.ReturnType, expression.Arguments.Skip(1))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.ListFill), 8, 4);\n+\n+            case nameof(NpgsqlArrayExtensions.MatrixFill):\n+                return VersionAtLeast(8, 4)\n+                    ? new SqlFunctionExpression(\"array_fill\", expression.Method.ReturnType, expression.Arguments.Skip(1))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.MatrixFill), 8, 4);\n+\n+            case nameof(NpgsqlArrayExtensions.ArrayDimensions):\n+                return VersionAtLeast(7, 4)\n+                    ? new SqlFunctionExpression(\"array_dims\", expression.Method.ReturnType, expression.Arguments.Skip(1).Take(1))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.ArrayDimensions), 7, 4);\n+\n+            case nameof(NpgsqlArrayExtensions.ArrayPositions):\n+                return VersionAtLeast(9, 5)\n+                    ? new SqlFunctionExpression(\"array_positions\", expression.Method.ReturnType, expression.Arguments.Skip(1))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.ArrayPositions), 9, 5);\n+\n+            case nameof(NpgsqlArrayExtensions.ArrayRemove):\n+                return VersionAtLeast(9, 3)\n+                    ? new SqlFunctionExpression(\"array_remove\", expression.Method.ReturnType, expression.Arguments.Skip(1).Take(2))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.ArrayRemove), 9, 3);\n+\n+            case nameof(NpgsqlArrayExtensions.ArrayReplace):\n+                return VersionAtLeast(9, 3)\n+                    ? new SqlFunctionExpression(\"array_replace\", expression.Method.ReturnType, expression.Arguments.Skip(1).Take(3))\n+                    : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.ArrayReplace), 9, 3);\n+\n+            case nameof(NpgsqlArrayExtensions.ArrayToString):\n+                return VersionAtLeast(9, 1)\n+                    ? new SqlFunctionExpression(\"array_to_string\", expression.Method.ReturnType, expression.Arguments.Skip(1).Take(3))\n+                    : VersionAtLeast(7, 4)\n+                        ? new SqlFunctionExpression(\"array_to_string\", expression.Method.ReturnType, expression.Arguments.Skip(1).Take(2))\n+                        : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.ArrayToString), 7, 4);\n+\n+            case nameof(NpgsqlArrayExtensions.StringToArray):\n+                return VersionAtLeast(9, 1)\n+                    ? new SqlFunctionExpression(\"string_to_array\", expression.Method.ReturnType, expression.Arguments.Skip(1).Take(3))\n+                    : VersionAtLeast(7, 4)\n+                        ? new SqlFunctionExpression(\"string_to_array\", expression.Method.ReturnType, expression.Arguments.Skip(1).Take(2))\n+                        : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.StringToArray), 7, 4);\n+\n+            case nameof(NpgsqlArrayExtensions.StringToList):\n+                return VersionAtLeast(9, 1)\n+                    ? new SqlFunctionExpression(\"string_to_array\", expression.Method.ReturnType, expression.Arguments.Skip(1).Take(3))\n+                    : VersionAtLeast(7, 4)\n+                        ? new SqlFunctionExpression(\"string_to_array\", expression.Method.ReturnType, expression.Arguments.Skip(1).Take(2))\n+                        : throw VersionNotSupportedException(nameof(NpgsqlArrayExtensions.StringToList), 7, 4);\n+\n+            default:\n+                return null;\n+            }\n+\n+            NotSupportedException VersionNotSupportedException(string name, int major, int minor)\n+                => new NotSupportedException($\"{nameof(NpgsqlArrayExtensions)}.{name} is not supported before PostgreSQL {major}.{minor}.\");\n+        }\n+\n+        /// <summary>\n+        /// Translates static methods defined on <see cref=\"Array\"/>.\n+        /// </summary>\n+        /// <param name=\"expression\">The expression to translate.</param>\n+        /// <returns>\n+        /// A translated expression or null if no translation is supported.\n+        /// </returns>\n+        [CanBeNull]\n+        Expression ArrayStaticHandler([NotNull] MethodCallExpression expression)\n+        {\n+            if (!expression.Method.IsStatic || expression.Method.DeclaringType != typeof(Array))\n+                return null;\n+\n+            switch (expression.Method.Name)\n+            {\n+            case nameof(Array.IndexOf) when VersionAtLeast(9, 5) &&\n+                                            expression.Arguments[0].Type.GetArrayRank() == 1 &&\n+                                            expression.Method.GetParameters().Length <= 3:\n+                return\n+                    Expression.Subtract(\n+                        Expression.Coalesce(\n+                            new SqlFunctionExpression(\n+                                \"array_position\",\n+                                typeof(int?),\n+                                expression.Arguments.Take(3)),\n+                            Expression.Constant(0)),\n+                        Expression.Constant(1));\n+\n+            default:\n+                return null;\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Translates instance methods defined on <see cref=\"Array\"/>.\n+        /// </summary>\n+        /// <param name=\"expression\">The expression to translate.</param>\n+        /// <returns>\n+        /// A translated expression or null if no translation is supported.\n+        /// </returns>\n+        [CanBeNull]\n+        Expression ArrayInstanceHandler([NotNull] MethodCallExpression expression)\n+        {\n+            var instance = expression.Object;\n+\n+            if (instance == null || !instance.Type.IsArray)\n+                return null;\n+\n+            switch (expression.Method.Name)\n+            {\n+            case nameof(Array.GetLength) when VersionAtLeast(8, 4):\n+                return\n+                    Expression.Coalesce(\n+                        new SqlFunctionExpression(\n+                            \"array_length\",\n+                            typeof(int?),\n+                            new[] { instance, GenerateOneBasedIndexExpression(expression.Arguments[0]) }),\n+                        Expression.Constant(0));\n+\n+            case nameof(Array.GetLowerBound) when VersionAtLeast(7, 4):\n+                return\n+                    Expression.Subtract(\n+                        Expression.Coalesce(\n+                            new SqlFunctionExpression(\n+                                \"array_lower\",\n+                                typeof(int?),\n+                                new[] { instance, GenerateOneBasedIndexExpression(expression.Arguments[0]) }),\n+                            Expression.Constant(0)),\n+                        Expression.Constant(1));\n+\n+            case nameof(Array.GetUpperBound) when VersionAtLeast(7, 4):\n+                return\n+                    Expression.Subtract(\n+                        Expression.Coalesce(\n+                            new SqlFunctionExpression(\n+                                \"array_upper\",\n+                                typeof(int?),\n+                                new[] { instance, GenerateOneBasedIndexExpression(expression.Arguments[0]) }),\n+                            Expression.Constant(0)),\n+                        Expression.Constant(1));\n+\n+            default:\n+                return null;\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Translates instance methods defined on <see cref=\"List{T}\"/>.\n+        /// </summary>\n+        /// <param name=\"expression\">The expression to translate.</param>\n+        /// <returns>\n+        /// A translated expression or null if no translation is supported.\n+        /// </returns>\n+        [CanBeNull]\n+        Expression ListInstanceHandler([NotNull] MethodCallExpression expression)\n+        {\n+            var instance = expression.Object;\n+\n+            if (instance == null || !instance.Type.IsGenericType || instance.Type.GetGenericTypeDefinition() != typeof(List<>))\n+                return null;\n+\n+            switch (expression.Method.Name)\n+            {\n+            case \"get_Item\":\n+                return MakeIndex(instance, expression.Arguments[0]);\n+\n+            case nameof(IList.IndexOf) when VersionAtLeast(9, 5):\n+                return\n+                    Expression.Subtract(\n+                        Expression.Coalesce(\n+                            new SqlFunctionExpression(\n+                                \"array_position\",\n+                                typeof(int?),\n+                                new[] { instance, expression.Arguments[0] }),\n+                            Expression.Constant(0)),\n+                        Expression.Constant(1));\n+\n+            default:\n+                return null;\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Translates instance methods defined on <see cref=\"string\"/>.\n+        /// </summary>\n+        /// <param name=\"expression\">The expression to translate.</param>\n+        /// <returns>\n+        /// A translated expression or null if no translation is supported.\n+        /// </returns>\n+        [CanBeNull]\n+        static Expression StringInstanceHandler([NotNull] MethodCallExpression expression)\n+        {\n+            var instance = expression.Object;\n+\n+            if (instance == null || instance.Type != typeof(string))\n+                return null;\n+\n+            switch (expression.Method.Name)\n+            {\n+            case \"get_Chars\":\n+                return MakeIndex(instance, expression.Arguments[0]);\n+\n+            default:\n+                return null;\n+            }\n+        }\n+\n+        #endregion\n+\n+        #region Helpers\n+\n+        /// <summary>\n+        /// True if <see cref=\"_postgresVersion\"/> is null, greater than, or equal to the specified version.\n+        /// </summary>\n+        /// <param name=\"major\">The major version.</param>\n+        /// <param name=\"minor\">The minor version.</param>\n+        /// <returns>\n+        /// True if <see cref=\"_postgresVersion\"/> is null, greater than, or equal to the specified version.\n+        /// </returns>\n+        bool VersionAtLeast(int major, int minor) => _postgresVersion is null || new Version(major, minor) <= _postgresVersion;\n+\n+        /// <summary>\n+        /// Creates an expression of type <see cref=\"T:ExpressionType.ArrayIndex\"/> or <see cref=\"T:ExpressionType.Index\"/>\n+        /// from the <paramref name=\"instance\"/> and the <paramref name=\"index\"/>.\n+        /// </summary>\n+        /// <param name=\"instance\">The instance to index.</param>\n+        /// <param name=\"index\">The index value.</param>\n+        /// <returns>\n+        /// An <see cref=\"T:ExpressionType.ArrayIndex\"/> or <see cref=\"T:ExpressionType.Index\"/>.\n+        /// </returns>\n+        [NotNull]\n+        static Expression MakeIndex([NotNull] Expression instance, [NotNull] Expression index)","path":"src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlArrayMethodCallTranslator.cs","position":375,"original_position":375,"commit_id":"c6ac0e02345729d950293eb3b6a58a2db87b5f4d","original_commit_id":"9d77bf3ba152221c843d13e982f45cbfacda11bf","user":{"login":"austindrenski","id":21338699,"node_id":"MDQ6VXNlcjIxMzM4Njk5","avatar_url":"https://avatars3.githubusercontent.com/u/21338699?v=4","gravatar_id":"","url":"https://api.github.com/users/austindrenski","html_url":"https://github.com/austindrenski","followers_url":"https://api.github.com/users/austindrenski/followers","following_url":"https://api.github.com/users/austindrenski/following{/other_user}","gists_url":"https://api.github.com/users/austindrenski/gists{/gist_id}","starred_url":"https://api.github.com/users/austindrenski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/austindrenski/subscriptions","organizations_url":"https://api.github.com/users/austindrenski/orgs","repos_url":"https://api.github.com/users/austindrenski/repos","events_url":"https://api.github.com/users/austindrenski/events{/privacy}","received_events_url":"https://api.github.com/users/austindrenski/received_events","type":"User","site_admin":false},"body":"Scratch that, still need the methods, but will split.","created_at":"2018-12-12T00:17:24Z","updated_at":"2018-12-12T00:17:25Z","html_url":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pull/541#discussion_r240841669","pull_request_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/541","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/comments/240841669"},"html":{"href":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pull/541#discussion_r240841669"},"pull_request":{"href":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/541"}},"in_reply_to_id":234539972},"pull_request":{"url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/541","id":203703308,"node_id":"MDExOlB1bGxSZXF1ZXN0MjAzNzAzMzA4","html_url":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pull/541","diff_url":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pull/541.diff","patch_url":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pull/541.patch","issue_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/541","number":541,"state":"open","locked":false,"title":"Map List<T> operations to PostgreSQL arrays","user":{"login":"austindrenski","id":21338699,"node_id":"MDQ6VXNlcjIxMzM4Njk5","avatar_url":"https://avatars3.githubusercontent.com/u/21338699?v=4","gravatar_id":"","url":"https://api.github.com/users/austindrenski","html_url":"https://github.com/austindrenski","followers_url":"https://api.github.com/users/austindrenski/followers","following_url":"https://api.github.com/users/austindrenski/following{/other_user}","gists_url":"https://api.github.com/users/austindrenski/gists{/gist_id}","starred_url":"https://api.github.com/users/austindrenski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/austindrenski/subscriptions","organizations_url":"https://api.github.com/users/austindrenski/orgs","repos_url":"https://api.github.com/users/austindrenski/repos","events_url":"https://api.github.com/users/austindrenski/events{/privacy}","received_events_url":"https://api.github.com/users/austindrenski/received_events","type":"User","site_admin":false},"body":"This is a subset of the work from #431 refactored without `IQueryOptimizer` or `NpgsqlExistsToAnyRewritingExpressionVisitor` per #460.\r\n\r\n## Compatibility\r\n\r\nOperator | PostgreSQL support\r\n-- | --\r\n`=` | 7.4+\r\n`<>` | 7.4+\r\n`<` | 7.4+\r\n`>` | 7.4+\r\n`<=` | 7.4+\r\n`>=` | 7.4+\r\n`@>` | 8.2+\r\n`<@` | 8.2+\r\n`&&` | 8.2+\r\n`\\|\\|` | 7.4+\r\n\r\nFunction | PostgreSQL support\r\n-- | --\r\n`array_append(anyarray, anyelement)` | see `\\|\\|`\r\n`cardinality(anyarray)` | 9.4+\r\n`array_cat(anyarray, anyarray)` | see `\\|\\|`\r\n`array_dims(anyarray)` | 7.4+\r\n`array_fill(anyelement, int[] [, int[]]) ` | 8.4+\r\n`array_length(anyarray, int)` | 8.4+\r\n`array_lower(anyarray, int)` | 7.4+\r\n`array_ndims(anyarray)` | 8.4+\r\n`array_position(anyarray, anyelement [, int])` | 9.5+\r\n`array_positions(anyarray, anyelement)` | 9.5+\r\n`array_prepend(anyelement, anyarray)` | see `\\|\\|`\r\n`array_remove(anyarray, anyelement)` | 9.3+\r\n`array_replace(anyarray, anyelement, anyelement)` | 9.3+\r\n`array_to_string (anyarray, text)` | 7.4-9.0\r\n`array_to_string(anyarray, text [, text])` | 9.1+\r\n`array_upper(anyarray, int)` | 7.4+\r\n`string_to_array (text, text)` | 7.4-9.0\r\n`string_to_array(text, text [, text])` | 9.1+\r\n\r\n### Postponed \r\nFunction | PostgreSQL support\r\n-- | -\r\n`array_agg(expression)` | 8.4+\r\n`unnest(anyarray)` | 8.4+\r\n`unnest(anyarray, anyarray [, ...])` | 9.4+\r\n\r\n## Related\r\n#395\r\n#431 \r\n#460 \r\n#542 \r\n#543 \r\n#544 \r\n#545 \r\n#549 \r\n#551 \r\n#552 \r\n\r\n","created_at":"2018-07-25T02:20:47Z","updated_at":"2018-12-12T00:17:24Z","closed_at":null,"merged_at":null,"merge_commit_sha":"07284b561018de306db61e849ab9dbe0e99050b2","assignee":{"login":"austindrenski","id":21338699,"node_id":"MDQ6VXNlcjIxMzM4Njk5","avatar_url":"https://avatars3.githubusercontent.com/u/21338699?v=4","gravatar_id":"","url":"https://api.github.com/users/austindrenski","html_url":"https://github.com/austindrenski","followers_url":"https://api.github.com/users/austindrenski/followers","following_url":"https://api.github.com/users/austindrenski/following{/other_user}","gists_url":"https://api.github.com/users/austindrenski/gists{/gist_id}","starred_url":"https://api.github.com/users/austindrenski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/austindrenski/subscriptions","organizations_url":"https://api.github.com/users/austindrenski/orgs","repos_url":"https://api.github.com/users/austindrenski/repos","events_url":"https://api.github.com/users/austindrenski/events{/privacy}","received_events_url":"https://api.github.com/users/austindrenski/received_events","type":"User","site_admin":false},"assignees":[{"login":"austindrenski","id":21338699,"node_id":"MDQ6VXNlcjIxMzM4Njk5","avatar_url":"https://avatars3.githubusercontent.com/u/21338699?v=4","gravatar_id":"","url":"https://api.github.com/users/austindrenski","html_url":"https://github.com/austindrenski","followers_url":"https://api.github.com/users/austindrenski/followers","following_url":"https://api.github.com/users/austindrenski/following{/other_user}","gists_url":"https://api.github.com/users/austindrenski/gists{/gist_id}","starred_url":"https://api.github.com/users/austindrenski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/austindrenski/subscriptions","organizations_url":"https://api.github.com/users/austindrenski/orgs","repos_url":"https://api.github.com/users/austindrenski/repos","events_url":"https://api.github.com/users/austindrenski/events{/privacy}","received_events_url":"https://api.github.com/users/austindrenski/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":358090613,"node_id":"MDU6TGFiZWwzNTgwOTA2MTM=","url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/labels/enhancement","name":"enhancement","color":"009800","default":true}],"milestone":{"url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/milestones/20","html_url":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/milestone/20","labels_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/milestones/20/labels","id":3754747,"node_id":"MDk6TWlsZXN0b25lMzc1NDc0Nw==","number":20,"title":"3.0.0","description":null,"creator":{"login":"austindrenski","id":21338699,"node_id":"MDQ6VXNlcjIxMzM4Njk5","avatar_url":"https://avatars3.githubusercontent.com/u/21338699?v=4","gravatar_id":"","url":"https://api.github.com/users/austindrenski","html_url":"https://github.com/austindrenski","followers_url":"https://api.github.com/users/austindrenski/followers","following_url":"https://api.github.com/users/austindrenski/following{/other_user}","gists_url":"https://api.github.com/users/austindrenski/gists{/gist_id}","starred_url":"https://api.github.com/users/austindrenski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/austindrenski/subscriptions","organizations_url":"https://api.github.com/users/austindrenski/orgs","repos_url":"https://api.github.com/users/austindrenski/repos","events_url":"https://api.github.com/users/austindrenski/events{/privacy}","received_events_url":"https://api.github.com/users/austindrenski/received_events","type":"User","site_admin":false},"open_issues":22,"closed_issues":2,"state":"open","created_at":"2018-10-21T18:00:51Z","updated_at":"2018-12-11T21:14:02Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/541/commits","review_comments_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/541/comments","review_comment_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/comments{/number}","comments_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/541/comments","statuses_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/statuses/c6ac0e02345729d950293eb3b6a58a2db87b5f4d","head":{"label":"austindrenski:list-operators","ref":"list-operators","sha":"c6ac0e02345729d950293eb3b6a58a2db87b5f4d","user":{"login":"austindrenski","id":21338699,"node_id":"MDQ6VXNlcjIxMzM4Njk5","avatar_url":"https://avatars3.githubusercontent.com/u/21338699?v=4","gravatar_id":"","url":"https://api.github.com/users/austindrenski","html_url":"https://github.com/austindrenski","followers_url":"https://api.github.com/users/austindrenski/followers","following_url":"https://api.github.com/users/austindrenski/following{/other_user}","gists_url":"https://api.github.com/users/austindrenski/gists{/gist_id}","starred_url":"https://api.github.com/users/austindrenski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/austindrenski/subscriptions","organizations_url":"https://api.github.com/users/austindrenski/orgs","repos_url":"https://api.github.com/users/austindrenski/repos","events_url":"https://api.github.com/users/austindrenski/events{/privacy}","received_events_url":"https://api.github.com/users/austindrenski/received_events","type":"User","site_admin":false},"repo":{"id":123528424,"node_id":"MDEwOlJlcG9zaXRvcnkxMjM1Mjg0MjQ=","name":"Npgsql.EntityFrameworkCore.PostgreSQL","full_name":"austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL","private":false,"owner":{"login":"austindrenski","id":21338699,"node_id":"MDQ6VXNlcjIxMzM4Njk5","avatar_url":"https://avatars3.githubusercontent.com/u/21338699?v=4","gravatar_id":"","url":"https://api.github.com/users/austindrenski","html_url":"https://github.com/austindrenski","followers_url":"https://api.github.com/users/austindrenski/followers","following_url":"https://api.github.com/users/austindrenski/following{/other_user}","gists_url":"https://api.github.com/users/austindrenski/gists{/gist_id}","starred_url":"https://api.github.com/users/austindrenski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/austindrenski/subscriptions","organizations_url":"https://api.github.com/users/austindrenski/orgs","repos_url":"https://api.github.com/users/austindrenski/repos","events_url":"https://api.github.com/users/austindrenski/events{/privacy}","received_events_url":"https://api.github.com/users/austindrenski/received_events","type":"User","site_admin":false},"html_url":"https://github.com/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL","description":"Entity Framework Core provider for PostgreSQL","fork":true,"url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL","forks_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/forks","keys_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/keys{/key_id}","collaborators_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/teams","hooks_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/hooks","issue_events_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/issues/events{/number}","events_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/events","assignees_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/assignees{/user}","branches_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/branches{/branch}","tags_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/tags","blobs_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/git/refs{/sha}","trees_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/git/trees{/sha}","statuses_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/statuses/{sha}","languages_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/languages","stargazers_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/stargazers","contributors_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/contributors","subscribers_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/subscribers","subscription_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/subscription","commits_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/commits{/sha}","git_commits_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/git/commits{/sha}","comments_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/comments{/number}","issue_comment_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/issues/comments{/number}","contents_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/contents/{+path}","compare_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/compare/{base}...{head}","merges_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/merges","archive_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/downloads","issues_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/issues{/number}","pulls_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/pulls{/number}","milestones_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/milestones{/number}","notifications_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/labels{/name}","releases_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/releases{/id}","deployments_url":"https://api.github.com/repos/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL/deployments","created_at":"2018-03-02T04:03:13Z","updated_at":"2018-12-11T22:46:54Z","pushed_at":"2018-12-11T22:46:52Z","git_url":"git://github.com/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL.git","ssh_url":"git@github.com:austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL.git","clone_url":"https://github.com/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL.git","svn_url":"https://github.com/austindrenski/Npgsql.EntityFrameworkCore.PostgreSQL","homepage":null,"size":2363,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"postgresql","name":"PostgreSQL License","spdx_id":"PostgreSQL","url":"https://api.github.com/licenses/postgresql","node_id":"MDc6TGljZW5zZTMx"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"dev"}},"base":{"label":"npgsql:dev","ref":"dev","sha":"4441b26c54b0aaba0db2557d210212f48a31f3fc","user":{"login":"npgsql","id":5766497,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU3NjY0OTc=","avatar_url":"https://avatars2.githubusercontent.com/u/5766497?v=4","gravatar_id":"","url":"https://api.github.com/users/npgsql","html_url":"https://github.com/npgsql","followers_url":"https://api.github.com/users/npgsql/followers","following_url":"https://api.github.com/users/npgsql/following{/other_user}","gists_url":"https://api.github.com/users/npgsql/gists{/gist_id}","starred_url":"https://api.github.com/users/npgsql/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/npgsql/subscriptions","organizations_url":"https://api.github.com/users/npgsql/orgs","repos_url":"https://api.github.com/users/npgsql/repos","events_url":"https://api.github.com/users/npgsql/events{/privacy}","received_events_url":"https://api.github.com/users/npgsql/received_events","type":"Organization","site_admin":false},"repo":{"id":55906763,"node_id":"MDEwOlJlcG9zaXRvcnk1NTkwNjc2Mw==","name":"Npgsql.EntityFrameworkCore.PostgreSQL","full_name":"npgsql/Npgsql.EntityFrameworkCore.PostgreSQL","private":false,"owner":{"login":"npgsql","id":5766497,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU3NjY0OTc=","avatar_url":"https://avatars2.githubusercontent.com/u/5766497?v=4","gravatar_id":"","url":"https://api.github.com/users/npgsql","html_url":"https://github.com/npgsql","followers_url":"https://api.github.com/users/npgsql/followers","following_url":"https://api.github.com/users/npgsql/following{/other_user}","gists_url":"https://api.github.com/users/npgsql/gists{/gist_id}","starred_url":"https://api.github.com/users/npgsql/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/npgsql/subscriptions","organizations_url":"https://api.github.com/users/npgsql/orgs","repos_url":"https://api.github.com/users/npgsql/repos","events_url":"https://api.github.com/users/npgsql/events{/privacy}","received_events_url":"https://api.github.com/users/npgsql/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL","description":"Entity Framework Core provider for PostgreSQL","fork":false,"url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL","forks_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/forks","keys_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/keys{/key_id}","collaborators_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/teams","hooks_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/hooks","issue_events_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/events{/number}","events_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/events","assignees_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/assignees{/user}","branches_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/branches{/branch}","tags_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/tags","blobs_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/git/refs{/sha}","trees_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/git/trees{/sha}","statuses_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/statuses/{sha}","languages_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/languages","stargazers_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/stargazers","contributors_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/contributors","subscribers_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/subscribers","subscription_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/subscription","commits_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/commits{/sha}","git_commits_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/git/commits{/sha}","comments_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/comments{/number}","issue_comment_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/comments{/number}","contents_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/contents/{+path}","compare_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/compare/{base}...{head}","merges_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/merges","archive_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/downloads","issues_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues{/number}","pulls_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls{/number}","milestones_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/milestones{/number}","notifications_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/labels{/name}","releases_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/releases{/id}","deployments_url":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/deployments","created_at":"2016-04-10T15:26:37Z","updated_at":"2018-12-11T22:44:54Z","pushed_at":"2018-12-11T22:44:51Z","git_url":"git://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL.git","ssh_url":"git@github.com:npgsql/Npgsql.EntityFrameworkCore.PostgreSQL.git","clone_url":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL.git","svn_url":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL","homepage":null,"size":2380,"stargazers_count":377,"watchers_count":377,"language":"C#","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":66,"mirror_url":null,"archived":false,"open_issues_count":61,"license":{"key":"postgresql","name":"PostgreSQL License","spdx_id":"PostgreSQL","url":"https://api.github.com/licenses/postgresql","node_id":"MDc6TGljZW5zZTMx"},"forks":66,"open_issues":61,"watchers":377,"default_branch":"dev"}},"_links":{"self":{"href":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/541"},"html":{"href":"https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pull/541"},"issue":{"href":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/541"},"comments":{"href":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/541/comments"},"review_comments":{"href":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/541/comments"},"review_comment":{"href":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/pulls/541/commits"},"statuses":{"href":"https://api.github.com/repos/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/statuses/c6ac0e02345729d950293eb3b6a58a2db87b5f4d"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"austindrenski"}}