From c0d71f8f868f746ca554312b04b7f1c042d6d03e Mon Sep 17 00:00:00 2001 From: Maksim Strebkov <257byte@gmail.com> Date: Wed, 21 Feb 2024 18:34:26 +0300 Subject: [PATCH] Add implicit sort by level for transactions and originations --- Tzkt.Api/Controllers/OperationsController.cs | 8 +-- Tzkt.Api/Repositories/AccountRepository.cs | 36 ++++++++--- .../OperationRepository.Originations.cs | 61 +++++++++++++++---- .../OperationRepository.Transactions.cs | 61 +++++++++++++++---- Tzkt.Api/Repositories/OperationRepository.cs | 6 ++ 5 files changed, 132 insertions(+), 40 deletions(-) diff --git a/Tzkt.Api/Controllers/OperationsController.cs b/Tzkt.Api/Controllers/OperationsController.cs index d307674ef..47bd9b8bc 100644 --- a/Tzkt.Api/Controllers/OperationsController.cs +++ b/Tzkt.Api/Controllers/OperationsController.cs @@ -2018,7 +2018,7 @@ public async Task>> GetOriginatio Int32Parameter typeHash, Int32Parameter codeHash, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, Int32Parameter senderCodeHash, Int32Parameter anyCodeHash, OperationStatusParameter status, @@ -2201,7 +2201,7 @@ public async Task>> GetOriginatio [HttpGet("originations/count")] public async Task> GetOriginationsCount( Int32Parameter level, - DateTimeParameter timestamp) + TimestampParameter timestamp) { if (level == null && timestamp == null) return Ok(State.Current.OriginationOpsCount); @@ -2260,7 +2260,7 @@ public async Task>> GetTransactio Int64Parameter amount, Int64Parameter id, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, Int32Parameter senderCodeHash, Int32Parameter targetCodeHash, Int32Parameter codeHash, @@ -2501,7 +2501,7 @@ public async Task> GetTransactionsCount( AccountParameter target, Int64Parameter amount, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, StringParameter entrypoint, JsonParameter parameter, OperationStatusParameter status) diff --git a/Tzkt.Api/Repositories/AccountRepository.cs b/Tzkt.Api/Repositories/AccountRepository.cs index 227772c2d..5cb9c967d 100644 --- a/Tzkt.Api/Repositories/AccountRepository.cs +++ b/Tzkt.Api/Repositories/AccountRepository.cs @@ -2158,6 +2158,22 @@ public async Task> GetOperations( limit = limit }; + TimestampParameter _timestamp = null; + if (timestamp != null) + { + _timestamp = new TimestampParameter + { + Eq = timestamp.Eq == null ? null : Time.FindLevel((DateTime)timestamp.Eq, SearchMode.Exact), + Ne = timestamp.Ne == null ? null : Time.FindLevel((DateTime)timestamp.Ne, SearchMode.Exact), + Gt = timestamp.Gt == null ? null : Time.FindLevel((DateTime)timestamp.Gt, SearchMode.ExactOrLower), + Ge = timestamp.Ge == null ? null : Time.FindLevel((DateTime)timestamp.Ge, SearchMode.ExactOrHigher), + Lt = timestamp.Lt == null ? null : Time.FindLevel((DateTime)timestamp.Lt, SearchMode.ExactOrHigher), + Le = timestamp.Le == null ? null : Time.FindLevel((DateTime)timestamp.Le, SearchMode.ExactOrLower), + In = timestamp.In?.Select(x => Time.FindLevel(x, SearchMode.Exact)).ToList(), + Ni = timestamp.Ni?.Select(x => Time.FindLevel(x, SearchMode.Exact)).ToList(), + }; + } + switch (account) { case RawDelegate delegat: @@ -2208,11 +2224,11 @@ public async Task> GetOperations( : Task.FromResult(Enumerable.Empty()); var originations = delegat.OriginationsCount > 0 && types.Contains(OpTypes.Origination) - ? Operations.GetOriginations(new AnyOfParameter { Fields = new[] { "initiator", "sender", "contractManager", "contractDelegate", "originatedContract" }, Eq = delegat.Id }, initiator, sender, contractManager, contractDelegate, originatedContract, null, null, null, level, timestamp, null, null, status, sort, offset, limit, format, quote) + ? Operations.GetOriginations(new AnyOfParameter { Fields = new[] { "initiator", "sender", "contractManager", "contractDelegate", "originatedContract" }, Eq = delegat.Id }, initiator, sender, contractManager, contractDelegate, originatedContract, null, null, null, level, _timestamp, null, null, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var transactions = delegat.TransactionsCount > 0 && types.Contains(OpTypes.Transaction) - ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "initiator", "sender", "target" }, Eq = delegat.Id }, initiator, sender, target, null, null, level, timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) + ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "initiator", "sender", "target" }, Eq = delegat.Id }, initiator, sender, target, null, null, level, _timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var reveals = delegat.RevealsCount > 0 && types.Contains(OpTypes.Reveal) @@ -2425,11 +2441,11 @@ await Task.WhenAll( : Task.FromResult(Enumerable.Empty()); var userOriginations = user.OriginationsCount > 0 && types.Contains(OpTypes.Origination) - ? Operations.GetOriginations(new AnyOfParameter { Fields = new[] { "initiator", "sender", "contractManager", "contractDelegate", "originatedContract" }, Eq = user.Id }, initiator, sender, contractManager, contractDelegate, originatedContract, null, null, null, level, timestamp, null, null, status, sort, offset, limit, format, quote) + ? Operations.GetOriginations(new AnyOfParameter { Fields = new[] { "initiator", "sender", "contractManager", "contractDelegate", "originatedContract" }, Eq = user.Id }, initiator, sender, contractManager, contractDelegate, originatedContract, null, null, null, level, _timestamp, null, null, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var userTransactions = user.TransactionsCount > 0 && types.Contains(OpTypes.Transaction) - ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "initiator", "sender", "target" }, Eq = user.Id }, initiator, sender, target, null, null, level, timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) + ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "initiator", "sender", "target" }, Eq = user.Id }, initiator, sender, target, null, null, level, _timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var userReveals = user.RevealsCount > 0 && types.Contains(OpTypes.Reveal) @@ -2590,19 +2606,19 @@ await Task.WhenAll( : Task.FromResult(Enumerable.Empty()); var contractOriginations = contract.OriginationsCount > 0 && types.Contains(OpTypes.Origination) - ? Operations.GetOriginations(new AnyOfParameter { Fields = new[] { "initiator", "sender", "contractManager", "contractDelegate", "originatedContract" }, Eq = contract.Id }, initiator, sender, contractManager, contractDelegate, originatedContract, null, null, null, level, timestamp, null, null, status, sort, offset, limit, format, quote) + ? Operations.GetOriginations(new AnyOfParameter { Fields = new[] { "initiator", "sender", "contractManager", "contractDelegate", "originatedContract" }, Eq = contract.Id }, initiator, sender, contractManager, contractDelegate, originatedContract, null, null, null, level, _timestamp, null, null, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var contractTransactions1 = contract.TransactionsCount > 0 && types.Contains(OpTypes.Transaction) && contract.Kind == 0 - ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "initiator" }, Eq = contract.Id }, initiator, sender, target, null, null, level, timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) + ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "initiator" }, Eq = contract.Id }, initiator, sender, target, null, null, level, _timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var contractTransactions2 = contract.TransactionsCount > 0 && types.Contains(OpTypes.Transaction) - ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "sender" }, Eq = contract.Id }, initiator, sender, target, null, null, level, timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) + ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "sender" }, Eq = contract.Id }, initiator, sender, target, null, null, level, _timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var contractTransactions3 = contract.TransactionsCount > 0 && types.Contains(OpTypes.Transaction) - ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "target" }, Eq = contract.Id }, initiator, sender, target, null, null, level, timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) + ? Operations.GetTransactions(new AnyOfParameter { Fields = new[] { "target" }, Eq = contract.Id }, initiator, sender, target, null, null, level, _timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var contractReveals = contract.RevealsCount > 0 && types.Contains(OpTypes.Reveal) @@ -2646,7 +2662,7 @@ await Task.WhenAll( var _rollup = new AccountParameter { Eq = rollup.Id }; var rollupTransactionOps = rollup.TransactionsCount> 0 && types.Contains(OpTypes.Transaction) - ? Operations.GetTransactions(null, null, null, _rollup, null, null, level, timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) + ? Operations.GetTransactions(null, null, null, _rollup, null, null, level, _timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var rollupTxRollupCommitOps = rollup.TxRollupCommitCount > 0 && types.Contains(OpTypes.TxRollupCommit) @@ -2708,7 +2724,7 @@ await Task.WhenAll( var _smartRollup = new SmartRollupParameter { Eq = smartRollup.Id }; var smartRollupTransactionOps = smartRollup.TransactionsCount > 0 && types.Contains(OpTypes.Transaction) - ? Operations.GetTransactions(new() { Fields = new[] { "sender", "target" }, Eq = smartRollup.Id }, null, null, null, null, null, level, timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) + ? Operations.GetTransactions(new() { Fields = new[] { "sender", "target" }, Eq = smartRollup.Id }, null, null, null, null, null, level, _timestamp, null, null, null, entrypoint, parameter, hasInternals, status, sort, offset, limit, format, quote) : Task.FromResult(Enumerable.Empty()); var smartRollupSrCementOps = smartRollup.SmartRollupCementCount > 0 && types.Contains(OpTypes.SmartRollupCement) diff --git a/Tzkt.Api/Repositories/OperationRepository.Originations.cs b/Tzkt.Api/Repositories/OperationRepository.Originations.cs index 239125e9f..02aefd749 100644 --- a/Tzkt.Api/Repositories/OperationRepository.Originations.cs +++ b/Tzkt.Api/Repositories/OperationRepository.Originations.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Dapper; +using Dapper; using Netezos.Encoding; using Tzkt.Api.Models; using Tzkt.Api.Services.Cache; @@ -20,11 +16,11 @@ public partial class OperationRepository : DbConnection public async Task GetOriginationsCount( Int32Parameter level, - DateTimeParameter timestamp) + TimestampParameter timestamp) { var sql = new SqlBuilder(@"SELECT COUNT(*) FROM ""OriginationOps""") .Filter("Level", level) - .Filter("Timestamp", timestamp); + .Filter("Level", timestamp); using var db = GetConnection(); return await db.QueryFirstAsync(sql.Query, sql.Params); @@ -370,7 +366,7 @@ public async Task> GetOriginations( Int32Parameter typeHash, Int32Parameter codeHash, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, Int32Parameter anyCodeHash, Int32Parameter senderCodeHash, OperationStatusParameter status, @@ -382,6 +378,19 @@ public async Task> GetOriginations( bool includeStorage = false, bool includeBigmaps = false) { + #region opts + if (ImplicitSortByLevel) + { + if ((level != null || timestamp != null) && offset?.Cr == null) + { + if (sort == null || sort.Asc == "id") + sort = new() { Asc = "level" }; + else if (sort.Desc == "id") + sort = new() { Desc = "level" }; + } + } + #endregion + var sql = new SqlBuilder($@" SELECT o.*, b.""Hash"" FROM ""OriginationOps"" AS o @@ -405,7 +414,7 @@ INNER JOIN ""Blocks"" as b .FilterA(@"c.""TypeHash""", typeHash) .FilterA(@"o.""ContractCodeHash""", codeHash) .FilterA(@"o.""Level""", level) - .FilterA(@"o.""Timestamp""", timestamp) + .FilterA(@"o.""Level""", timestamp) .FilterA(@"o.""SenderCodeHash""", senderCodeHash) .Filter("Status", status) .FilterOrA(new[] { @"o.""SenderCodeHash""", @"o.""ContractCodeHash""" }, anyCodeHash) @@ -502,7 +511,7 @@ public async Task GetOriginations( Int32Parameter typeHash, Int32Parameter codeHash, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, Int32Parameter anyCodeHash, Int32Parameter senderCodeHash, OperationStatusParameter status, @@ -569,6 +578,19 @@ public async Task GetOriginations( if (typeHash != null || codeHash != null) joins.Add(@"LEFT JOIN ""Accounts"" as c ON c.""Id"" = o.""ContractId"""); + #region opts + if (ImplicitSortByLevel) + { + if ((level != null || timestamp != null) && offset?.Cr == null) + { + if (sort == null || sort.Asc == "id") + sort = new() { Asc = "level" }; + else if (sort.Desc == "id") + sort = new() { Desc = "level" }; + } + } + #endregion + var sql = new SqlBuilder($@"SELECT {string.Join(',', columns)} FROM ""OriginationOps"" as o {string.Join(' ', joins)}") .Filter(anyof, x => x switch { @@ -587,7 +609,7 @@ public async Task GetOriginations( .FilterA(@"c.""TypeHash""", typeHash) .FilterA(@"o.""ContractCodeHash""", codeHash) .FilterA(@"o.""Level""", level) - .FilterA(@"o.""Timestamp""", timestamp) + .FilterA(@"o.""Level""", timestamp) .FilterA(@"o.""SenderCodeHash""", senderCodeHash) .Filter("Status", status) .FilterOrA(new[] { @"o.""SenderCodeHash""", @"o.""ContractCodeHash""" }, anyCodeHash) @@ -779,7 +801,7 @@ public async Task GetOriginations( Int32Parameter typeHash, Int32Parameter codeHash, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, Int32Parameter anyCodeHash, Int32Parameter senderCodeHash, OperationStatusParameter status, @@ -843,6 +865,19 @@ public async Task GetOriginations( if (typeHash != null || codeHash != null) joins.Add(@"LEFT JOIN ""Accounts"" as c ON c.""Id"" = o.""ContractId"""); + #region opts + if (ImplicitSortByLevel) + { + if ((level != null || timestamp != null) && offset?.Cr == null) + { + if (sort == null || sort.Asc == "id") + sort = new() { Asc = "level" }; + else if (sort.Desc == "id") + sort = new() { Desc = "level" }; + } + } + #endregion + var sql = new SqlBuilder($@"SELECT {string.Join(',', columns)} FROM ""OriginationOps"" as o {string.Join(' ', joins)}") .Filter(anyof, x => x switch { @@ -861,7 +896,7 @@ public async Task GetOriginations( .FilterA(@"c.""TypeHash""", typeHash) .FilterA(@"o.""ContractCodeHash""", codeHash) .FilterA(@"o.""Level""", level) - .FilterA(@"o.""Timestamp""", timestamp) + .FilterA(@"o.""Level""", timestamp) .FilterA(@"o.""SenderCodeHash""", senderCodeHash) .Filter("Status", status) .FilterOrA(new[] { @"o.""SenderCodeHash""", @"o.""ContractCodeHash""" }, anyCodeHash) diff --git a/Tzkt.Api/Repositories/OperationRepository.Transactions.cs b/Tzkt.Api/Repositories/OperationRepository.Transactions.cs index ef0bdaa1a..276044a8e 100644 --- a/Tzkt.Api/Repositories/OperationRepository.Transactions.cs +++ b/Tzkt.Api/Repositories/OperationRepository.Transactions.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Dapper; +using Dapper; using Netezos.Encoding; using Tzkt.Api.Models; using Tzkt.Data; @@ -24,7 +20,7 @@ public async Task GetTransactionsCount( AccountParameter target, Int64Parameter amount, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, StringParameter entrypoint, JsonParameter parameter, OperationStatusParameter status) @@ -36,7 +32,7 @@ public async Task GetTransactionsCount( .Filter("TargetId", target, x => x == "sender" ? "SenderId" : "InitiatorId") .Filter("Amount", amount) .Filter("Level", level) - .Filter("Timestamp", timestamp) + .Filter("Level", timestamp) .Filter("Entrypoint", entrypoint) .Filter("JsonParameters", parameter) .Filter("Status", status); @@ -336,7 +332,7 @@ public async Task> GetTransactions( Int64Parameter amount, Int64Parameter id, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, Int32Parameter codeHash, Int32Parameter senderCodeHash, Int32Parameter targetCodeHash, @@ -352,6 +348,19 @@ public async Task> GetTransactions( bool includeStorage = false, bool includeBigmaps = false) { + #region opts + if (ImplicitSortByLevel) + { + if ((level != null || timestamp != null) && offset?.Cr == null) + { + if (sort == null || sort.Asc == "id") + sort = new() { Asc = "level" }; + else if (sort.Desc == "id") + sort = new() { Desc = "level" }; + } + } + #endregion + var sql = new SqlBuilder(@" SELECT o.*, b.""Hash"" FROM ""TransactionOps"" AS o @@ -372,7 +381,7 @@ INNER JOIN ""Blocks"" as b .Filter("Status", status) .FilterA(@"o.""Id""", id) .FilterA(@"o.""Level""", level) - .FilterA(@"o.""Timestamp""", timestamp) + .FilterA(@"o.""Level""", timestamp) .FilterA(@"o.""SenderCodeHash""", senderCodeHash) .FilterA(@"o.""TargetCodeHash""", targetCodeHash) .FilterOrA(new[] { @"o.""SenderCodeHash""", @"o.""TargetCodeHash""" }, codeHash) @@ -466,7 +475,7 @@ public async Task GetTransactions( Int64Parameter amount, Int64Parameter id, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, Int32Parameter codeHash, Int32Parameter senderCodeHash, Int32Parameter targetCodeHash, @@ -544,6 +553,19 @@ public async Task GetTransactions( if (columns.Count == 0) return Array.Empty(); + #region opts + if (ImplicitSortByLevel) + { + if ((level != null || timestamp != null) && offset?.Cr == null) + { + if (sort == null || sort.Asc == "id") + sort = new() { Asc = "level" }; + else if (sort.Desc == "id") + sort = new() { Desc = "level" }; + } + } + #endregion + var sql = new SqlBuilder($@"SELECT {string.Join(',', columns)} FROM ""TransactionOps"" as o {string.Join(' ', joins)}") .Filter(anyof, x => x == "sender" ? "SenderId" : x == "target" ? "TargetId" : "InitiatorId") .Filter("InitiatorId", initiator, x => "TargetId") @@ -560,7 +582,7 @@ public async Task GetTransactions( .Filter("Status", status) .FilterA(@"o.""Id""", id) .FilterA(@"o.""Level""", level) - .FilterA(@"o.""Timestamp""", timestamp) + .FilterA(@"o.""Level""", timestamp) .FilterA(@"o.""SenderCodeHash""", senderCodeHash) .FilterA(@"o.""TargetCodeHash""", targetCodeHash) .FilterOrA(new[] { @"o.""SenderCodeHash""", @"o.""TargetCodeHash""" }, codeHash) @@ -750,7 +772,7 @@ public async Task GetTransactions( Int64Parameter amount, Int64Parameter id, Int32Parameter level, - DateTimeParameter timestamp, + TimestampParameter timestamp, Int32Parameter codeHash, Int32Parameter senderCodeHash, Int32Parameter targetCodeHash, @@ -825,6 +847,19 @@ public async Task GetTransactions( if (columns.Count == 0) return Array.Empty(); + #region opts + if (ImplicitSortByLevel) + { + if ((level != null || timestamp != null) && offset?.Cr == null) + { + if (sort == null || sort.Asc == "id") + sort = new() { Asc = "level" }; + else if (sort.Desc == "id") + sort = new() { Desc = "level" }; + } + } + #endregion + var sql = new SqlBuilder($@"SELECT {string.Join(',', columns)} FROM ""TransactionOps"" as o {string.Join(' ', joins)}") .Filter(anyof, x => x == "sender" ? "SenderId" : x == "target" ? "TargetId" : "InitiatorId") .Filter("InitiatorId", initiator, x => "TargetId") @@ -841,7 +876,7 @@ public async Task GetTransactions( .Filter("Status", status) .FilterA(@"o.""Id""", id) .FilterA(@"o.""Level""", level) - .FilterA(@"o.""Timestamp""", timestamp) + .FilterA(@"o.""Level""", timestamp) .FilterA(@"o.""SenderCodeHash""", senderCodeHash) .FilterA(@"o.""TargetCodeHash""", targetCodeHash) .FilterOrA(new[] { @"o.""SenderCodeHash""", @"o.""TargetCodeHash""" }, codeHash) diff --git a/Tzkt.Api/Repositories/OperationRepository.cs b/Tzkt.Api/Repositories/OperationRepository.cs index 65c9912e4..013908db9 100644 --- a/Tzkt.Api/Repositories/OperationRepository.cs +++ b/Tzkt.Api/Repositories/OperationRepository.cs @@ -11,12 +11,18 @@ public partial class OperationRepository : DbConnection readonly AccountsCache Accounts; readonly TimeCache Times; readonly QuotesCache Quotes; + readonly IConfiguration Config; + + #region options + bool ImplicitSortByLevel => Config.GetValue("Opts:ImplicitSortByLevel") == true; + #endregion public OperationRepository(AccountsCache accounts, TimeCache times, QuotesCache quotes, IConfiguration config) : base(config) { Accounts = accounts; Times = times; Quotes = quotes; + Config = config; } static async Task GetStatus(IDbConnection db, string table, string hash)