diff --git a/api/api.go b/api/api.go index 45e86ca..0fd16d7 100644 --- a/api/api.go +++ b/api/api.go @@ -30,7 +30,7 @@ type QueryParams struct { // @Description Map of filter parameters FilterParams map[string]string `schema:"-"` // @Description Field to group results by - GroupBy string `schema:"group_by"` + GroupBy []string `schema:"group_by"` // @Description Field to sort results by SortBy string `schema:"sort_by"` // @Description Sort order (asc or desc) @@ -70,7 +70,7 @@ type QueryResponse struct { // @Description Query result data Data interface{} `json:"data,omitempty"` // @Description Aggregation results - Aggregations map[string]string `json:"aggregations,omitempty"` + Aggregations []map[string]interface{} `json:"aggregations,omitempty"` } func writeError(w http.ResponseWriter, message string, code int) { diff --git a/internal/handlers/logs_handlers.go b/internal/handlers/logs_handlers.go index dbbc3b5..e4db770 100644 --- a/internal/handlers/logs_handlers.go +++ b/internal/handlers/logs_handlers.go @@ -133,39 +133,59 @@ func handleLogsRequest(c *gin.Context, contractAddress, signature string) { return } - logs, err := mainStorage.GetLogs(storage.QueryFilter{ + // Prepare the QueryFilter + qf := storage.QueryFilter{ FilterParams: queryParams.FilterParams, - GroupBy: []string{queryParams.GroupBy}, + ContractAddress: contractAddress, + Signature: signatureHash, + ChainId: chainId, SortBy: queryParams.SortBy, SortOrder: queryParams.SortOrder, Page: queryParams.Page, Limit: queryParams.Limit, - Aggregates: queryParams.Aggregates, - ContractAddress: contractAddress, - Signature: signatureHash, - ChainId: chainId, - }) - if err != nil { - log.Error().Err(err).Msg("Error querying logs") - api.InternalErrorHandler(c) - return } - response := api.QueryResponse{ + // Initialize the QueryResult + queryResult := api.QueryResponse{ Meta: api.Meta{ ChainId: chainId.Uint64(), ContractAddress: contractAddress, Signature: signatureHash, Page: queryParams.Page, Limit: queryParams.Limit, - TotalItems: len(logs.Data), + TotalItems: 0, TotalPages: 0, // TODO: Implement total pages count }, - Data: logs.Data, - Aggregations: logs.Aggregates, + Data: nil, + Aggregations: nil, + } + + // If aggregates or groupings are specified, retrieve them + if len(queryParams.Aggregates) > 0 || len(queryParams.GroupBy) > 0 { + qf.Aggregates = queryParams.Aggregates + qf.GroupBy = queryParams.GroupBy + + aggregatesResult, err := mainStorage.GetAggregations("logs", qf) + if err != nil { + log.Error().Err(err).Msg("Error querying aggregates") + api.InternalErrorHandler(c) + return + } + queryResult.Aggregations = aggregatesResult.Aggregates + queryResult.Meta.TotalItems = len(aggregatesResult.Aggregates) + } else { + // Retrieve logs data + logsResult, err := mainStorage.GetLogs(qf) + if err != nil { + log.Error().Err(err).Msg("Error querying logs") + api.InternalErrorHandler(c) + return + } + queryResult.Data = logsResult.Data + queryResult.Meta.TotalItems = len(logsResult.Data) } - sendJSONResponse(c, response) + sendJSONResponse(c, queryResult) } func getMainStorage() (storage.IMainStorage, error) { diff --git a/internal/handlers/transactions_handlers.go b/internal/handlers/transactions_handlers.go index 04fd937..284e17d 100644 --- a/internal/handlers/transactions_handlers.go +++ b/internal/handlers/transactions_handlers.go @@ -134,37 +134,57 @@ func handleTransactionsRequest(c *gin.Context, contractAddress, signature string return } - result, err := mainStorage.GetTransactions(storage.QueryFilter{ + // Prepare the QueryFilter + qf := storage.QueryFilter{ FilterParams: queryParams.FilterParams, - GroupBy: []string{queryParams.GroupBy}, + ContractAddress: contractAddress, + Signature: signatureHash, + ChainId: chainId, SortBy: queryParams.SortBy, SortOrder: queryParams.SortOrder, Page: queryParams.Page, Limit: queryParams.Limit, - Aggregates: queryParams.Aggregates, - ContractAddress: contractAddress, - Signature: signatureHash, - ChainId: chainId, - }) - if err != nil { - log.Error().Err(err).Msg("Error querying transactions") - api.InternalErrorHandler(c) - return } - response := api.QueryResponse{ + // Initialize the QueryResult + queryResult := api.QueryResponse{ Meta: api.Meta{ ChainId: chainId.Uint64(), ContractAddress: contractAddress, - Signature: signature, + Signature: signatureHash, Page: queryParams.Page, Limit: queryParams.Limit, - TotalItems: 0, // TODO: Implement total items count + TotalItems: 0, TotalPages: 0, // TODO: Implement total pages count }, - Data: result.Data, - Aggregations: result.Aggregates, + Data: nil, + Aggregations: nil, + } + + // If aggregates or groupings are specified, retrieve them + if len(queryParams.Aggregates) > 0 || len(queryParams.GroupBy) > 0 { + qf.Aggregates = queryParams.Aggregates + qf.GroupBy = queryParams.GroupBy + + aggregatesResult, err := mainStorage.GetAggregations("transactions", qf) + if err != nil { + log.Error().Err(err).Msg("Error querying aggregates") + api.InternalErrorHandler(c) + return + } + queryResult.Aggregations = aggregatesResult.Aggregates + queryResult.Meta.TotalItems = len(aggregatesResult.Aggregates) + } else { + // Retrieve logs data + transactionsResult, err := mainStorage.GetTransactions(qf) + if err != nil { + log.Error().Err(err).Msg("Error querying tran") + api.InternalErrorHandler(c) + return + } + queryResult.Data = transactionsResult.Data + queryResult.Meta.TotalItems = len(transactionsResult.Data) } - c.JSON(http.StatusOK, response) + c.JSON(http.StatusOK, queryResult) } diff --git a/internal/storage/clickhouse.go b/internal/storage/clickhouse.go index a3b5d1d..320f5ed 100644 --- a/internal/storage/clickhouse.go +++ b/internal/storage/clickhouse.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "math/big" + "reflect" "strings" "sync" "time" @@ -347,6 +348,76 @@ func (c *ClickHouseConnector) GetLogs(qf QueryFilter) (QueryResult[common.Log], return executeQuery[common.Log](c, "logs", columns, qf, scanLog) } +func (c *ClickHouseConnector) GetAggregations(table string, qf QueryFilter) (QueryResult[interface{}], error) { + // Build the SELECT clause with aggregates + selectColumns := strings.Join(append(qf.GroupBy, qf.Aggregates...), ", ") + query := fmt.Sprintf("SELECT %s FROM %s.%s WHERE is_deleted = 0", selectColumns, c.cfg.Database, table) + + // Apply filters + if qf.ChainId != nil && qf.ChainId.Sign() > 0 { + query = addFilterParams("chain_id", qf.ChainId.String(), query) + } + query = addContractAddress(table, query, qf.ContractAddress) + if qf.Signature != "" { + query += fmt.Sprintf(" AND topic_0 = '%s'", qf.Signature) + } + for key, value := range qf.FilterParams { + query = addFilterParams(key, strings.ToLower(value), query) + } + if len(qf.GroupBy) > 0 { + groupByColumns := strings.Join(qf.GroupBy, ", ") + query += fmt.Sprintf(" GROUP BY %s", groupByColumns) + } + + // Execute the query + rows, err := c.conn.Query(context.Background(), query) + if err != nil { + return QueryResult[interface{}]{}, err + } + defer rows.Close() + + columnNames := rows.Columns() + columnTypes := rows.ColumnTypes() + + // Collect results + var aggregates []map[string]interface{} + for rows.Next() { + values := make([]interface{}, len(columnNames)) + + // Assign Go types based on ClickHouse types + for i, colType := range columnTypes { + dbType := colType.DatabaseTypeName() + values[i] = mapClickHouseTypeToGoType(dbType) + } + + if err := rows.Scan(values...); err != nil { + return QueryResult[interface{}]{}, fmt.Errorf("failed to scan row: %w", err) + } + + // Prepare the result map for the current row + result := make(map[string]interface{}) + for i, colName := range columnNames { + valuePtr := values[i] + value := getUnderlyingValue(valuePtr) + + // Convert *big.Int to string + if bigIntValue, ok := value.(big.Int); ok { + result[colName] = BigInt{Int: bigIntValue} + } else { + result[colName] = value + } + } + + aggregates = append(aggregates, result) + } + + if err := rows.Err(); err != nil { + return QueryResult[interface{}]{}, fmt.Errorf("row iteration error: %w", err) + } + + return QueryResult[interface{}]{Data: nil, Aggregates: aggregates}, nil +} + func executeQuery[T any](c *ClickHouseConnector, table, columns string, qf QueryFilter, scanFunc func(driver.Rows) (T, error)) (QueryResult[T], error) { query := c.buildQuery(table, columns, qf) @@ -357,8 +428,7 @@ func executeQuery[T any](c *ClickHouseConnector, table, columns string, qf Query defer rows.Close() queryResult := QueryResult[T]{ - Data: []T{}, - Aggregates: map[string]string{}, + Data: []T{}, } for rows.Next() { @@ -369,21 +439,13 @@ func executeQuery[T any](c *ClickHouseConnector, table, columns string, qf Query queryResult.Data = append(queryResult.Data, item) } - if len(qf.Aggregates) > 0 { - aggregates, err := c.executeAggregateQuery(table, qf) - if err != nil { - return queryResult, err - } - queryResult.Aggregates = aggregates - } - return queryResult, nil } func (c *ClickHouseConnector) buildQuery(table, columns string, qf QueryFilter) string { query := fmt.Sprintf("SELECT %s FROM %s.%s WHERE is_deleted = 0", columns, c.cfg.Database, table) - if qf.ChainId.Sign() > 0 { + if qf.ChainId != nil && qf.ChainId.Sign() > 0 { query = addFilterParams("chain_id", qf.ChainId.String(), query) } query = addContractAddress(table, query, qf.ContractAddress) @@ -397,7 +459,7 @@ func (c *ClickHouseConnector) buildQuery(table, columns string, qf QueryFilter) query = addFilterParams(key, strings.ToLower(value), query) } - // Add sort by clause + // Add ORDER BY clause if qf.SortBy != "" { query += fmt.Sprintf(" ORDER BY %s %s", qf.SortBy, qf.SortOrder) } @@ -406,9 +468,8 @@ func (c *ClickHouseConnector) buildQuery(table, columns string, qf QueryFilter) if qf.Page > 0 && qf.Limit > 0 { offset := (qf.Page - 1) * qf.Limit query += fmt.Sprintf(" LIMIT %d OFFSET %d", qf.Limit, offset) - } else { - // Add limit clause - query += getLimitClause(int(qf.Limit)) + } else if qf.Limit > 0 { + query += fmt.Sprintf(" LIMIT %d", qf.Limit) } return query @@ -468,35 +529,6 @@ func getTopicValueFormat(topic string) string { return result } -func (c *ClickHouseConnector) executeAggregateQuery(table string, qf QueryFilter) (map[string]string, error) { - aggregateQuery := "SELECT " + strings.Join(qf.Aggregates, ", ") + - fmt.Sprintf(" FROM %s.%s WHERE is_deleted = 0", c.cfg.Database, table) - - if qf.ContractAddress != "" { - aggregateQuery += fmt.Sprintf(" AND address = '%s'", qf.ContractAddress) - } - if qf.Signature != "" { - aggregateQuery += fmt.Sprintf(" AND topic_0 = '%s'", qf.Signature) - } - for key, value := range qf.FilterParams { - aggregateQuery += fmt.Sprintf(" AND %s = '%s'", key, value) - } - - row := c.conn.QueryRow(context.Background(), aggregateQuery) - aggregateResultsJSON, err := json.Marshal(row) - if err != nil { - return nil, fmt.Errorf("error marshaling aggregate results to JSON: %w", err) - } - - var aggregateResultsMap map[string]string - err = json.Unmarshal(aggregateResultsJSON, &aggregateResultsMap) - if err != nil { - return nil, fmt.Errorf("error unmarshaling aggregate results JSON to map: %w", err) - } - - return aggregateResultsMap, nil -} - func scanTransaction(rows driver.Rows) (common.Transaction, error) { var tx common.Transaction err := rows.Scan( @@ -1037,3 +1069,165 @@ func (c *ClickHouseConnector) InsertBlockData(data *[]common.BlockData) error { } return nil } + +func mapClickHouseTypeToGoType(dbType string) interface{} { + // Handle LowCardinality types + if strings.HasPrefix(dbType, "LowCardinality(") { + dbType = dbType[len("LowCardinality(") : len(dbType)-1] + } + + // Handle Nullable types + isNullable := false + if strings.HasPrefix(dbType, "Nullable(") { + isNullable = true + dbType = dbType[len("Nullable(") : len(dbType)-1] + } + + // Handle Array types + if strings.HasPrefix(dbType, "Array(") { + elementType := dbType[len("Array(") : len(dbType)-1] + // For arrays, we'll use slices of pointers to the element type + switch elementType { + case "String", "FixedString": + return new([]*string) + case "Int8", "Int16", "Int32", "Int64": + return new([]*int64) + case "UInt8", "UInt16", "UInt32", "UInt64": + return new([]*uint64) + case "Float32", "Float64": + return new([]*float64) + case "Decimal", "Decimal32", "Decimal64", "Decimal128", "Decimal256": + return new([]*big.Float) + // Add more cases as needed + default: + return new([]interface{}) + } + } + + // Handle parameterized types by extracting the base type + baseType := dbType + if idx := strings.Index(dbType, "("); idx != -1 { + baseType = dbType[:idx] + } + + // Map basic data types + switch baseType { + // Signed integers + case "Int8": + if isNullable { + return new(*int8) + } + return new(int8) + case "Int16": + if isNullable { + return new(*int16) + } + return new(int16) + case "Int32": + if isNullable { + return new(*int32) + } + return new(int32) + case "Int64": + if isNullable { + return new(*int64) + } + return new(int64) + // Unsigned integers + case "UInt8": + if isNullable { + return new(*uint8) + } + return new(uint8) + case "UInt16": + if isNullable { + return new(*uint16) + } + return new(uint16) + case "UInt32": + if isNullable { + return new(*uint32) + } + return new(uint32) + case "UInt64": + if isNullable { + return new(*uint64) + } + return new(uint64) + // Floating-point numbers + case "Float32": + if isNullable { + return new(*float32) + } + return new(float32) + case "Float64": + if isNullable { + return new(*float64) + } + return new(float64) + // Decimal types + case "Decimal", "Decimal32", "Decimal64", "Decimal128", "Decimal256": + if isNullable { + return new(*big.Float) + } + return new(big.Float) + // String types + case "String", "FixedString", "UUID", "IPv4", "IPv6": + if isNullable { + return new(*string) + } + return new(string) + // Enums + case "Enum8", "Enum16": + if isNullable { + return new(*string) + } + return new(string) + // Date and time types + case "Date", "Date32", "DateTime", "DateTime64": + if isNullable { + return new(*time.Time) + } + return new(time.Time) + // Big integers + case "Int128", "UInt128", "Int256", "UInt256": + if isNullable { + return new(*big.Int) + } + return new(big.Int) + default: + // For unknown types, use interface{} + return new(interface{}) + } +} + +type BigInt struct { + big.Int +} + +func (b BigInt) MarshalJSON() ([]byte, error) { + return []byte(`"` + b.String() + `"`), nil +} + +func getUnderlyingValue(valuePtr interface{}) interface{} { + v := reflect.ValueOf(valuePtr) + + // Handle nil values + if !v.IsValid() { + return nil + } + + // Handle pointers and interfaces + for { + if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + if v.IsNil() { + return nil + } + v = v.Elem() + continue + } + break + } + + return v.Interface() +} diff --git a/internal/storage/clickhouse_connector_test.go b/internal/storage/clickhouse_connector_test.go new file mode 100644 index 0000000..cad416a --- /dev/null +++ b/internal/storage/clickhouse_connector_test.go @@ -0,0 +1,134 @@ +package storage + +import ( + "math/big" + "reflect" + "testing" + "time" +) + +// TestMapClickHouseTypeToGoType tests the mapClickHouseTypeToGoType function +func TestMapClickHouseTypeToGoType(t *testing.T) { + testCases := []struct { + dbType string + expectedType interface{} + }{ + // Signed integers + {"Int8", int8(0)}, + {"Nullable(Int8)", (**int8)(nil)}, + {"Int16", int16(0)}, + {"Nullable(Int16)", (**int16)(nil)}, + {"Int32", int32(0)}, + {"Nullable(Int32)", (**int32)(nil)}, + {"Int64", int64(0)}, + {"Nullable(Int64)", (**int64)(nil)}, + // Unsigned integers + {"UInt8", uint8(0)}, + {"Nullable(UInt8)", (**uint8)(nil)}, + {"UInt16", uint16(0)}, + {"Nullable(UInt16)", (**uint16)(nil)}, + {"UInt32", uint32(0)}, + {"Nullable(UInt32)", (**uint32)(nil)}, + {"UInt64", uint64(0)}, + {"Nullable(UInt64)", (**uint64)(nil)}, + // Big integers + {"Int128", big.NewInt(0)}, + {"Nullable(Int128)", (**big.Int)(nil)}, + {"UInt128", big.NewInt(0)}, + {"Nullable(UInt128)", (**big.Int)(nil)}, + {"Int256", big.NewInt(0)}, + {"Nullable(Int256)", (**big.Int)(nil)}, + {"UInt256", big.NewInt(0)}, + {"Nullable(UInt256)", (**big.Int)(nil)}, + // Floating-point numbers + {"Float32", float32(0)}, + {"Nullable(Float32)", (**float32)(nil)}, + {"Float64", float64(0)}, + {"Nullable(Float64)", (**float64)(nil)}, + // Decimal types + {"Decimal", big.NewFloat(0)}, + {"Nullable(Decimal)", (**big.Float)(nil)}, + {"Decimal32", big.NewFloat(0)}, + {"Nullable(Decimal32)", (**big.Float)(nil)}, + {"Decimal64", big.NewFloat(0)}, + {"Nullable(Decimal64)", (**big.Float)(nil)}, + {"Decimal128", big.NewFloat(0)}, + {"Nullable(Decimal128)", (**big.Float)(nil)}, + {"Decimal256", big.NewFloat(0)}, + {"Nullable(Decimal256)", (**big.Float)(nil)}, + // String types + {"String", ""}, + {"Nullable(String)", (**string)(nil)}, + {"FixedString(42)", ""}, + {"Nullable(FixedString(42))", (**string)(nil)}, + {"UUID", ""}, + {"Nullable(UUID)", (**string)(nil)}, + {"IPv4", ""}, + {"Nullable(IPv4)", (**string)(nil)}, + {"IPv6", ""}, + {"Nullable(IPv6)", (**string)(nil)}, + // Date and time types + {"Date", time.Time{}}, + {"Nullable(Date)", (**time.Time)(nil)}, + {"DateTime", time.Time{}}, + {"Nullable(DateTime)", (**time.Time)(nil)}, + {"DateTime64", time.Time{}}, + {"Nullable(DateTime64)", (**time.Time)(nil)}, + // Enums + {"Enum8('a' = 1, 'b' = 2)", ""}, + {"Nullable(Enum8('a' = 1, 'b' = 2))", (**string)(nil)}, + {"Enum16('a' = 1, 'b' = 2)", ""}, + {"Nullable(Enum16('a' = 1, 'b' = 2))", (**string)(nil)}, + // Arrays + {"Array(Int32)", &[]*int64{}}, + {"Array(String)", &[]*string{}}, + {"Array(Float64)", &[]*float64{}}, + // LowCardinality + {"LowCardinality(String)", ""}, + {"LowCardinality(Nullable(String))", (**string)(nil)}, + // Unknown type + {"UnknownType", new(interface{})}, + {"Nullable(UnknownType)", new(interface{})}, + } + + for _, tc := range testCases { + t.Run(tc.dbType, func(t *testing.T) { + result := mapClickHouseTypeToGoType(tc.dbType) + + expectedType := reflect.TypeOf(tc.expectedType) + resultType := reflect.TypeOf(result) + + // Handle pointers + if expectedType.Kind() == reflect.Ptr { + if resultType.Kind() != reflect.Ptr { + t.Errorf("Expected pointer type for dbType %s, got %s", tc.dbType, resultType.Kind()) + return + } + expectedElemType := expectedType.Elem() + resultElemType := resultType.Elem() + if expectedElemType.Kind() == reflect.Ptr { + // Expected pointer to pointer + if resultElemType.Kind() != reflect.Ptr { + t.Errorf("Expected pointer to pointer for dbType %s, got %s", tc.dbType, resultElemType.Kind()) + return + } + expectedElemType = expectedElemType.Elem() + resultElemType = resultElemType.Elem() + } + if expectedElemType != resultElemType { + t.Errorf("Type mismatch for dbType %s: expected %s, got %s", tc.dbType, expectedElemType, resultElemType) + } + } else { + // Non-pointer types + if resultType.Kind() != reflect.Ptr { + t.Errorf("Expected pointer type for dbType %s, got %s", tc.dbType, resultType.Kind()) + return + } + resultElemType := resultType.Elem() + if expectedType != resultElemType { + t.Errorf("Type mismatch for dbType %s: expected %s, got %s", tc.dbType, expectedType, resultElemType) + } + } + }) + } +} diff --git a/internal/storage/connector.go b/internal/storage/connector.go index baf9fb2..86cddbf 100644 --- a/internal/storage/connector.go +++ b/internal/storage/connector.go @@ -18,16 +18,17 @@ type QueryFilter struct { Page int Limit int Offset int - Aggregates []string + Aggregates []string // e.g., ["COUNT(*) AS count", "SUM(amount) AS total_amount"] FromAddress string ContractAddress string Signature string } type QueryResult[T any] struct { // TODO: findout how to only allow Log/transaction arrays or split the result - Data []T `json:"data"` - Aggregates map[string]string `json:"aggregates"` + Data []T `json:"data"` + Aggregates []map[string]interface{} `json:"aggregates"` } + type IStorage struct { OrchestratorStorage IOrchestratorStorage MainStorage IMainStorage @@ -55,6 +56,7 @@ type IMainStorage interface { GetBlocks(qf QueryFilter) (blocks []common.Block, err error) GetTransactions(qf QueryFilter) (transactions QueryResult[common.Transaction], err error) GetLogs(qf QueryFilter) (logs QueryResult[common.Log], err error) + GetAggregations(table string, qf QueryFilter) (QueryResult[interface{}], error) GetTraces(qf QueryFilter) (traces []common.Trace, err error) GetMaxBlockNumber(chainId *big.Int) (maxBlockNumber *big.Int, err error) /** diff --git a/test/mocks/MockIMainStorage.go b/test/mocks/MockIMainStorage.go index 8800917..5423841 100644 --- a/test/mocks/MockIMainStorage.go +++ b/test/mocks/MockIMainStorage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.2. DO NOT EDIT. +// Code generated by mockery v2.46.3. DO NOT EDIT. //go:build !production @@ -73,6 +73,63 @@ func (_c *MockIMainStorage_DeleteBlockData_Call) RunAndReturn(run func(*big.Int, return _c } +// GetAggregations provides a mock function with given fields: table, qf +func (_m *MockIMainStorage) GetAggregations(table string, qf storage.QueryFilter) (storage.QueryResult[interface{}], error) { + ret := _m.Called(table, qf) + + if len(ret) == 0 { + panic("no return value specified for GetAggregations") + } + + var r0 storage.QueryResult[interface{}] + var r1 error + if rf, ok := ret.Get(0).(func(string, storage.QueryFilter) (storage.QueryResult[interface{}], error)); ok { + return rf(table, qf) + } + if rf, ok := ret.Get(0).(func(string, storage.QueryFilter) storage.QueryResult[interface{}]); ok { + r0 = rf(table, qf) + } else { + r0 = ret.Get(0).(storage.QueryResult[interface{}]) + } + + if rf, ok := ret.Get(1).(func(string, storage.QueryFilter) error); ok { + r1 = rf(table, qf) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockIMainStorage_GetAggregations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAggregations' +type MockIMainStorage_GetAggregations_Call struct { + *mock.Call +} + +// GetAggregations is a helper method to define mock.On call +// - table string +// - qf storage.QueryFilter +func (_e *MockIMainStorage_Expecter) GetAggregations(table interface{}, qf interface{}) *MockIMainStorage_GetAggregations_Call { + return &MockIMainStorage_GetAggregations_Call{Call: _e.mock.On("GetAggregations", table, qf)} +} + +func (_c *MockIMainStorage_GetAggregations_Call) Run(run func(table string, qf storage.QueryFilter)) *MockIMainStorage_GetAggregations_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(storage.QueryFilter)) + }) + return _c +} + +func (_c *MockIMainStorage_GetAggregations_Call) Return(_a0 storage.QueryResult[interface{}], _a1 error) *MockIMainStorage_GetAggregations_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockIMainStorage_GetAggregations_Call) RunAndReturn(run func(string, storage.QueryFilter) (storage.QueryResult[interface{}], error)) *MockIMainStorage_GetAggregations_Call { + _c.Call.Return(run) + return _c +} + // GetBlocks provides a mock function with given fields: qf func (_m *MockIMainStorage) GetBlocks(qf storage.QueryFilter) ([]common.Block, error) { ret := _m.Called(qf) diff --git a/test/mocks/MockIOrchestratorStorage.go b/test/mocks/MockIOrchestratorStorage.go index 284134a..84b9003 100644 --- a/test/mocks/MockIOrchestratorStorage.go +++ b/test/mocks/MockIOrchestratorStorage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.2. DO NOT EDIT. +// Code generated by mockery v2.46.3. DO NOT EDIT. //go:build !production diff --git a/test/mocks/MockIRPCClient.go b/test/mocks/MockIRPCClient.go index 5a078ed..4b062a7 100644 --- a/test/mocks/MockIRPCClient.go +++ b/test/mocks/MockIRPCClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.2. DO NOT EDIT. +// Code generated by mockery v2.46.3. DO NOT EDIT. //go:build !production diff --git a/test/mocks/MockIStagingStorage.go b/test/mocks/MockIStagingStorage.go index 969967a..dc0a55b 100644 --- a/test/mocks/MockIStagingStorage.go +++ b/test/mocks/MockIStagingStorage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.2. DO NOT EDIT. +// Code generated by mockery v2.46.3. DO NOT EDIT. //go:build !production