{"action":"created","comment":{"url":"https://api.github.com/repos/lykkecloud/MT/pulls/comments/213213702","pull_request_review_id":150000740,"id":213213702,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxMzIxMzcwMg==","diff_hunk":"@@ -0,0 +1,148 @@\n+﻿using System;\n+using System.Data.SqlClient;\n+using System.Linq;\n+using System.Threading.Tasks;\n+using Common;\n+using Common.Log;\n+using Dapper;\n+using MarginTrading.Backend.Core;\n+using MarginTrading.Backend.Core.Repositories;\n+using MarginTrading.Common.Services;\n+using MarginTrading.SqlRepositories.Entities;\n+using Microsoft.Extensions.Internal;\n+using Newtonsoft.Json;\n+using Newtonsoft.Json.Linq;\n+\n+namespace MarginTrading.SqlRepositories.Repositories\n+{\n+    public class OperationExecutionInfoRepository : IOperationExecutionInfoRepository\n+    {\n+        private const string TableName = \"MarginTradingExecutionInfo\";\n+        private const string CreateTableScript = \"CREATE TABLE [{0}](\" +\n+                                                 \"[Oid] [bigint] NOT NULL IDENTITY(1,1) PRIMARY KEY,\" +\n+                                                 \"[Id] [nvarchar] (64) NOT NULL,\" +\n+                                                 \"[LastModified] [datetime] NOT NULL, \" +\n+                                                 \"[OperationName] [nvarchar] (64) NULL, \" +\n+                                                 \"[Version] [nvarchar] (64) NULL, \" +\n+                                                 \"[Data] [nvarchar] (MAX) NOT NULL,\" +\n+                                                 \"CONSTRAINT [MTEx_Id] UNIQUE NONCLUSTERED ([Id], [OperationName])\" +\n+                                                 \");\";\n+        \n+        private static Type DataType => typeof(IOperationExecutionInfo<object>);\n+        private static readonly string GetColumns = string.Join(\",\", DataType.GetProperties().Select(x => x.Name));\n+        private static readonly string GetFields = string.Join(\",\", DataType.GetProperties().Select(x => \"@\" + x.Name));\n+        private static readonly string GetUpdateClause = string.Join(\",\", \n+            DataType.GetProperties().Select(x => \"[\" + x.Name + \"]=@\" + x.Name));\n+\n+        private readonly string _connectionString;\n+        private readonly ILog _log;\n+        private readonly IDateService _dateService;\n+\n+        public OperationExecutionInfoRepository( \n+            string connectionString, \n+            ILog log,\n+            IDateService dateService)\n+        {\n+            _connectionString = connectionString;\n+            _log = log;\n+            _dateService = dateService;\n+            \n+            using (var conn = new SqlConnection(_connectionString))\n+            {\n+                try { conn.CreateTableIfDoesntExists(CreateTableScript, TableName); }\n+                catch (Exception ex)\n+                {\n+                    _log?.WriteErrorAsync(nameof(OperationExecutionInfoRepository), \"CreateTableIfDoesntExists\", null, ex);\n+                    throw;\n+                }\n+            }\n+        }\n+        \n+        public async Task<IOperationExecutionInfo<TData>> GetOrAddAsync<TData>(\n+            string operationName, string operationId, Func<IOperationExecutionInfo<TData>> factory) where TData : class\n+        {\n+            try\n+            {\n+                using (var conn = new SqlConnection(_connectionString))\n+                {\n+                    var operationInfo = await conn.QueryFirstOrDefaultAsync<OperationExecutionInfoEntity>(\n+                        $\"SELECT * FROM {TableName} WHERE Id=@operationId and OperationName=@operationName\",\n+                        new {operationId, operationName});\n+\n+                    if (operationInfo == null)\n+                    {\n+                        var entity = Convert(factory());\n+                        entity.LastModified = _dateService.Now();\n+\n+                        await conn.ExecuteAsync(\n+                            $\"insert into {TableName} ({GetColumns}) values ({GetFields})\", entity);\n+\n+                        return Convert<TData>(entity);\n+                    }\n+\n+                    return Convert<TData>(operationInfo);\n+                }\n+            }\n+            catch (Exception ex)\n+            {\n+                await _log.WriteErrorAsync(nameof(OperationExecutionInfoRepository), nameof(GetOrAddAsync), ex);\n+                throw;\n+            }\n+        }\n+\n+        public async Task<IOperationExecutionInfo<TData>> GetAsync<TData>(string operationName, string id) where TData : class\n+        {\n+            using (var conn = new SqlConnection(_connectionString))\n+            {\n+                var operationInfo = await conn.QuerySingleOrDefaultAsync<OperationExecutionInfoEntity>(\n+                    $\"SELECT * FROM {TableName} WHERE Id = @id and OperationName=@operationName\",\n+                    new {id, operationName});\n+\n+                return operationInfo == null ? null : Convert<TData>(operationInfo);\n+            }\n+        }\n+\n+        public async Task Save<TData>(IOperationExecutionInfo<TData> executionInfo) where TData : class\n+        {\n+            var entity = Convert(executionInfo);\n+            entity.LastModified = _dateService.Now();\n+            \n+            using (var conn = new SqlConnection(_connectionString))\n+            {\n+                try\n+                {\n+                    await conn.ExecuteAsync(\n+                        $\"insert into {TableName} ({GetColumns}) values ({GetFields})\", entity);\n+                }\n+                catch (SqlException)\n+                {\n+                    await conn.ExecuteAsync(\n+                        $\"update {TableName} set {GetUpdateClause} where Id=@Id\", entity);","path":"src/MarginTrading.SqlRepositories/Repositories/OperationExecutionInfoRepository.cs","position":120,"original_position":120,"commit_id":"15124119f065ab5330c60daa156f6f12fd53cfe7","original_commit_id":"15124119f065ab5330c60daa156f6f12fd53cfe7","user":{"login":"andrey-anokhin","id":18243836,"node_id":"MDQ6VXNlcjE4MjQzODM2","avatar_url":"https://avatars1.githubusercontent.com/u/18243836?v=4","gravatar_id":"","url":"https://api.github.com/users/andrey-anokhin","html_url":"https://github.com/andrey-anokhin","followers_url":"https://api.github.com/users/andrey-anokhin/followers","following_url":"https://api.github.com/users/andrey-anokhin/following{/other_user}","gists_url":"https://api.github.com/users/andrey-anokhin/gists{/gist_id}","starred_url":"https://api.github.com/users/andrey-anokhin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/andrey-anokhin/subscriptions","organizations_url":"https://api.github.com/users/andrey-anokhin/orgs","repos_url":"https://api.github.com/users/andrey-anokhin/repos","events_url":"https://api.github.com/users/andrey-anokhin/events{/privacy}","received_events_url":"https://api.github.com/users/andrey-anokhin/received_events","type":"User","site_admin":false},"body":"OperationName=@operationName is missed","created_at":"2018-08-28T07:47:00Z","updated_at":"2018-08-28T07:47:11Z","html_url":"https://github.com/lykkecloud/MT/pull/56#discussion_r213213702","pull_request_url":"https://api.github.com/repos/lykkecloud/MT/pulls/56","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/lykkecloud/MT/pulls/comments/213213702"},"html":{"href":"https://github.com/lykkecloud/MT/pull/56#discussion_r213213702"},"pull_request":{"href":"https://api.github.com/repos/lykkecloud/MT/pulls/56"}}},"pull_request":{"url":"https://api.github.com/repos/lykkecloud/MT/pulls/56","id":211118347,"node_id":"MDExOlB1bGxSZXF1ZXN0MjExMTE4MzQ3","html_url":"https://github.com/lykkecloud/MT/pull/56","diff_url":"https://github.com/lykkecloud/MT/pull/56.diff","patch_url":"https://github.com/lykkecloud/MT/pull/56.patch","issue_url":"https://api.github.com/repos/lykkecloud/MT/issues/56","number":56,"state":"open","locked":false,"title":"Feature mtc 303 withdrawal idempotency","user":{"login":"GSailen","id":3401283,"node_id":"MDQ6VXNlcjM0MDEyODM=","avatar_url":"https://avatars2.githubusercontent.com/u/3401283?v=4","gravatar_id":"","url":"https://api.github.com/users/GSailen","html_url":"https://github.com/GSailen","followers_url":"https://api.github.com/users/GSailen/followers","following_url":"https://api.github.com/users/GSailen/following{/other_user}","gists_url":"https://api.github.com/users/GSailen/gists{/gist_id}","starred_url":"https://api.github.com/users/GSailen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GSailen/subscriptions","organizations_url":"https://api.github.com/users/GSailen/orgs","repos_url":"https://api.github.com/users/GSailen/repos","events_url":"https://api.github.com/users/GSailen/events{/privacy}","received_events_url":"https://api.github.com/users/GSailen/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-08-27T13:57:17Z","updated_at":"2018-08-28T07:47:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"13040055777ddec6abd31069675f49c26cee496e","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/lykkecloud/MT/pulls/56/commits","review_comments_url":"https://api.github.com/repos/lykkecloud/MT/pulls/56/comments","review_comment_url":"https://api.github.com/repos/lykkecloud/MT/pulls/comments{/number}","comments_url":"https://api.github.com/repos/lykkecloud/MT/issues/56/comments","statuses_url":"https://api.github.com/repos/lykkecloud/MT/statuses/15124119f065ab5330c60daa156f6f12fd53cfe7","head":{"label":"lykkecloud:feature_MTC-303-Withdrawal-Idempotency","ref":"feature_MTC-303-Withdrawal-Idempotency","sha":"15124119f065ab5330c60daa156f6f12fd53cfe7","user":{"login":"lykkecloud","id":37992979,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3OTkyOTc5","avatar_url":"https://avatars1.githubusercontent.com/u/37992979?v=4","gravatar_id":"","url":"https://api.github.com/users/lykkecloud","html_url":"https://github.com/lykkecloud","followers_url":"https://api.github.com/users/lykkecloud/followers","following_url":"https://api.github.com/users/lykkecloud/following{/other_user}","gists_url":"https://api.github.com/users/lykkecloud/gists{/gist_id}","starred_url":"https://api.github.com/users/lykkecloud/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lykkecloud/subscriptions","organizations_url":"https://api.github.com/users/lykkecloud/orgs","repos_url":"https://api.github.com/users/lykkecloud/repos","events_url":"https://api.github.com/users/lykkecloud/events{/privacy}","received_events_url":"https://api.github.com/users/lykkecloud/received_events","type":"Organization","site_admin":false},"repo":{"id":127700684,"node_id":"MDEwOlJlcG9zaXRvcnkxMjc3MDA2ODQ=","name":"MT","full_name":"lykkecloud/MT","owner":{"login":"lykkecloud","id":37992979,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3OTkyOTc5","avatar_url":"https://avatars1.githubusercontent.com/u/37992979?v=4","gravatar_id":"","url":"https://api.github.com/users/lykkecloud","html_url":"https://github.com/lykkecloud","followers_url":"https://api.github.com/users/lykkecloud/followers","following_url":"https://api.github.com/users/lykkecloud/following{/other_user}","gists_url":"https://api.github.com/users/lykkecloud/gists{/gist_id}","starred_url":"https://api.github.com/users/lykkecloud/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lykkecloud/subscriptions","organizations_url":"https://api.github.com/users/lykkecloud/orgs","repos_url":"https://api.github.com/users/lykkecloud/repos","events_url":"https://api.github.com/users/lykkecloud/events{/privacy}","received_events_url":"https://api.github.com/users/lykkecloud/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/lykkecloud/MT","description":"Margin Trading Platform","fork":true,"url":"https://api.github.com/repos/lykkecloud/MT","forks_url":"https://api.github.com/repos/lykkecloud/MT/forks","keys_url":"https://api.github.com/repos/lykkecloud/MT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lykkecloud/MT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lykkecloud/MT/teams","hooks_url":"https://api.github.com/repos/lykkecloud/MT/hooks","issue_events_url":"https://api.github.com/repos/lykkecloud/MT/issues/events{/number}","events_url":"https://api.github.com/repos/lykkecloud/MT/events","assignees_url":"https://api.github.com/repos/lykkecloud/MT/assignees{/user}","branches_url":"https://api.github.com/repos/lykkecloud/MT/branches{/branch}","tags_url":"https://api.github.com/repos/lykkecloud/MT/tags","blobs_url":"https://api.github.com/repos/lykkecloud/MT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lykkecloud/MT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lykkecloud/MT/git/refs{/sha}","trees_url":"https://api.github.com/repos/lykkecloud/MT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lykkecloud/MT/statuses/{sha}","languages_url":"https://api.github.com/repos/lykkecloud/MT/languages","stargazers_url":"https://api.github.com/repos/lykkecloud/MT/stargazers","contributors_url":"https://api.github.com/repos/lykkecloud/MT/contributors","subscribers_url":"https://api.github.com/repos/lykkecloud/MT/subscribers","subscription_url":"https://api.github.com/repos/lykkecloud/MT/subscription","commits_url":"https://api.github.com/repos/lykkecloud/MT/commits{/sha}","git_commits_url":"https://api.github.com/repos/lykkecloud/MT/git/commits{/sha}","comments_url":"https://api.github.com/repos/lykkecloud/MT/comments{/number}","issue_comment_url":"https://api.github.com/repos/lykkecloud/MT/issues/comments{/number}","contents_url":"https://api.github.com/repos/lykkecloud/MT/contents/{+path}","compare_url":"https://api.github.com/repos/lykkecloud/MT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lykkecloud/MT/merges","archive_url":"https://api.github.com/repos/lykkecloud/MT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lykkecloud/MT/downloads","issues_url":"https://api.github.com/repos/lykkecloud/MT/issues{/number}","pulls_url":"https://api.github.com/repos/lykkecloud/MT/pulls{/number}","milestones_url":"https://api.github.com/repos/lykkecloud/MT/milestones{/number}","notifications_url":"https://api.github.com/repos/lykkecloud/MT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lykkecloud/MT/labels{/name}","releases_url":"https://api.github.com/repos/lykkecloud/MT/releases{/id}","deployments_url":"https://api.github.com/repos/lykkecloud/MT/deployments","created_at":"2018-04-02T04:01:16Z","updated_at":"2018-08-22T10:00:23Z","pushed_at":"2018-08-27T16:35:02Z","git_url":"git://github.com/lykkecloud/MT.git","ssh_url":"git@github.com:lykkecloud/MT.git","clone_url":"https://github.com/lykkecloud/MT.git","svn_url":"https://github.com/lykkecloud/MT","homepage":null,"size":3180,"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":4,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":4,"watchers":0,"default_branch":"master"}},"base":{"label":"lykkecloud:master","ref":"master","sha":"58f1bd0559452ac8e2afb68ff2a1ed0ba9296c44","user":{"login":"lykkecloud","id":37992979,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3OTkyOTc5","avatar_url":"https://avatars1.githubusercontent.com/u/37992979?v=4","gravatar_id":"","url":"https://api.github.com/users/lykkecloud","html_url":"https://github.com/lykkecloud","followers_url":"https://api.github.com/users/lykkecloud/followers","following_url":"https://api.github.com/users/lykkecloud/following{/other_user}","gists_url":"https://api.github.com/users/lykkecloud/gists{/gist_id}","starred_url":"https://api.github.com/users/lykkecloud/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lykkecloud/subscriptions","organizations_url":"https://api.github.com/users/lykkecloud/orgs","repos_url":"https://api.github.com/users/lykkecloud/repos","events_url":"https://api.github.com/users/lykkecloud/events{/privacy}","received_events_url":"https://api.github.com/users/lykkecloud/received_events","type":"Organization","site_admin":false},"repo":{"id":127700684,"node_id":"MDEwOlJlcG9zaXRvcnkxMjc3MDA2ODQ=","name":"MT","full_name":"lykkecloud/MT","owner":{"login":"lykkecloud","id":37992979,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM3OTkyOTc5","avatar_url":"https://avatars1.githubusercontent.com/u/37992979?v=4","gravatar_id":"","url":"https://api.github.com/users/lykkecloud","html_url":"https://github.com/lykkecloud","followers_url":"https://api.github.com/users/lykkecloud/followers","following_url":"https://api.github.com/users/lykkecloud/following{/other_user}","gists_url":"https://api.github.com/users/lykkecloud/gists{/gist_id}","starred_url":"https://api.github.com/users/lykkecloud/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lykkecloud/subscriptions","organizations_url":"https://api.github.com/users/lykkecloud/orgs","repos_url":"https://api.github.com/users/lykkecloud/repos","events_url":"https://api.github.com/users/lykkecloud/events{/privacy}","received_events_url":"https://api.github.com/users/lykkecloud/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/lykkecloud/MT","description":"Margin Trading Platform","fork":true,"url":"https://api.github.com/repos/lykkecloud/MT","forks_url":"https://api.github.com/repos/lykkecloud/MT/forks","keys_url":"https://api.github.com/repos/lykkecloud/MT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lykkecloud/MT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lykkecloud/MT/teams","hooks_url":"https://api.github.com/repos/lykkecloud/MT/hooks","issue_events_url":"https://api.github.com/repos/lykkecloud/MT/issues/events{/number}","events_url":"https://api.github.com/repos/lykkecloud/MT/events","assignees_url":"https://api.github.com/repos/lykkecloud/MT/assignees{/user}","branches_url":"https://api.github.com/repos/lykkecloud/MT/branches{/branch}","tags_url":"https://api.github.com/repos/lykkecloud/MT/tags","blobs_url":"https://api.github.com/repos/lykkecloud/MT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lykkecloud/MT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lykkecloud/MT/git/refs{/sha}","trees_url":"https://api.github.com/repos/lykkecloud/MT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lykkecloud/MT/statuses/{sha}","languages_url":"https://api.github.com/repos/lykkecloud/MT/languages","stargazers_url":"https://api.github.com/repos/lykkecloud/MT/stargazers","contributors_url":"https://api.github.com/repos/lykkecloud/MT/contributors","subscribers_url":"https://api.github.com/repos/lykkecloud/MT/subscribers","subscription_url":"https://api.github.com/repos/lykkecloud/MT/subscription","commits_url":"https://api.github.com/repos/lykkecloud/MT/commits{/sha}","git_commits_url":"https://api.github.com/repos/lykkecloud/MT/git/commits{/sha}","comments_url":"https://api.github.com/repos/lykkecloud/MT/comments{/number}","issue_comment_url":"https://api.github.com/repos/lykkecloud/MT/issues/comments{/number}","contents_url":"https://api.github.com/repos/lykkecloud/MT/contents/{+path}","compare_url":"https://api.github.com/repos/lykkecloud/MT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lykkecloud/MT/merges","archive_url":"https://api.github.com/repos/lykkecloud/MT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lykkecloud/MT/downloads","issues_url":"https://api.github.com/repos/lykkecloud/MT/issues{/number}","pulls_url":"https://api.github.com/repos/lykkecloud/MT/pulls{/number}","milestones_url":"https://api.github.com/repos/lykkecloud/MT/milestones{/number}","notifications_url":"https://api.github.com/repos/lykkecloud/MT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lykkecloud/MT/labels{/name}","releases_url":"https://api.github.com/repos/lykkecloud/MT/releases{/id}","deployments_url":"https://api.github.com/repos/lykkecloud/MT/deployments","created_at":"2018-04-02T04:01:16Z","updated_at":"2018-08-22T10:00:23Z","pushed_at":"2018-08-27T16:35:02Z","git_url":"git://github.com/lykkecloud/MT.git","ssh_url":"git@github.com:lykkecloud/MT.git","clone_url":"https://github.com/lykkecloud/MT.git","svn_url":"https://github.com/lykkecloud/MT","homepage":null,"size":3180,"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":4,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":4,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/lykkecloud/MT/pulls/56"},"html":{"href":"https://github.com/lykkecloud/MT/pull/56"},"issue":{"href":"https://api.github.com/repos/lykkecloud/MT/issues/56"},"comments":{"href":"https://api.github.com/repos/lykkecloud/MT/issues/56/comments"},"review_comments":{"href":"https://api.github.com/repos/lykkecloud/MT/pulls/56/comments"},"review_comment":{"href":"https://api.github.com/repos/lykkecloud/MT/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/lykkecloud/MT/pulls/56/commits"},"statuses":{"href":"https://api.github.com/repos/lykkecloud/MT/statuses/15124119f065ab5330c60daa156f6f12fd53cfe7"}},"author_association":"NONE"}}
{"actor":{"display_login":"andrey-anokhin"}}