From ce2deb8401a40a66ad59682c11d1f4c832a294f8 Mon Sep 17 00:00:00 2001 From: r-vdp Date: Thu, 11 Dec 2025 16:00:28 +0100 Subject: [PATCH 1/6] Remove unneeded init code --- query/types.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/query/types.go b/query/types.go index b872e66..3a8487f 100644 --- a/query/types.go +++ b/query/types.go @@ -7,20 +7,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) -var defaultColumns map[string]string - -func init() { - columns := []string{ - "entity_key", - "from_block", - } - - defaultColumns = make(map[string]string, len(columns)) - for _, column := range columns { - defaultColumns[column] = column - } -} - var KeyAttributeKey = "$key" var CreatorAttributeKey = "$creator" var OwnerAttributeKey = "$owner" From d216f8da959f7c3d1d54dcd173a069cf00e56b04 Mon Sep 17 00:00:00 2001 From: r-vdp Date: Thu, 11 Dec 2025 16:00:50 +0100 Subject: [PATCH 2/6] Don't run queries with a separate context --- sqlstore/sqlstore.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sqlstore/sqlstore.go b/sqlstore/sqlstore.go index 9565ed7..db1219b 100644 --- a/sqlstore/sqlstore.go +++ b/sqlstore/sqlstore.go @@ -195,10 +195,7 @@ func (s *SQLStore) QueryEntitiesInternalIterator( ) error { s.log.Info("Executing query", "query", queryStr, "args", args) - queryCtx, queryCtxCancel := context.WithCancel(ctx) - defer queryCtxCancel() - - rows, err := s.db.QueryContext(queryCtx, queryStr, args...) + rows, err := s.db.QueryContext(ctx, queryStr, args...) if err != nil { return fmt.Errorf("failed to get entities for query: %s: %w", queryStr, err) } From 5a39a55368069264c67bc864f035187aaee2c5b2 Mon Sep 17 00:00:00 2001 From: r-vdp Date: Thu, 11 Dec 2025 16:01:31 +0100 Subject: [PATCH 3/6] Correctly decode byte columns from the cursor --- query/cursor.go | 16 +++++++++++++++- query/query_options.go | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/query/cursor.go b/query/cursor.go index a7f0210..5290084 100644 --- a/query/cursor.go +++ b/query/cursor.go @@ -1,6 +1,7 @@ package query import ( + "encoding/base64" "encoding/hex" "encoding/json" "fmt" @@ -100,9 +101,22 @@ func (opts *QueryOptions) DecodeCursor(cursorStr string) (*Cursor, error) { return nil, fmt.Errorf("unknown value for descending: %d", descendingInt) } + value := c[1] + if opts.Columns[columnIx].IsBytes { + encoded, ok := value.(string) + if !ok { + return nil, fmt.Errorf("failed to decode cursor, byte column is not a string") + } + decoded, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return nil, fmt.Errorf("failed to decode cursor: %w", err) + } + value = decoded + } + cursor.ColumnValues = append(cursor.ColumnValues, CursorValue{ ColumnName: opts.Columns[columnIx].Name, - Value: c[1], + Value: value, Descending: descending, }) } diff --git a/query/query_options.go b/query/query_options.go index 6b4628e..8abfce4 100644 --- a/query/query_options.go +++ b/query/query_options.go @@ -20,6 +20,8 @@ const MaxResponseSize int = 512 * 1024 * 1024 type Column struct { Name string QualifiedName string + // If this is a byte column, we need to decode it when we get it from the json-encoded cursor + IsBytes bool } func (c Column) selector() string { @@ -67,6 +69,7 @@ func NewQueryOptions(log *slog.Logger, latestHead uint64, options *InternalQuery queryOptions.Columns = append(queryOptions.Columns, Column{ Name: "entity_key", QualifiedName: "e.entity_key", + IsBytes: true, }) if options.IncludeData.Payload { @@ -151,6 +154,7 @@ func NewQueryOptions(log *slog.Logger, latestHead uint64, options *InternalQuery Column: Column{ Name: "entity_key", QualifiedName: "e.entity_key", + IsBytes: true, }, }) From 102ce5ca1254290770002f9ce034f6c2bc4cb0d8 Mon Sep 17 00:00:00 2001 From: r-vdp Date: Thu, 11 Dec 2025 16:01:55 +0100 Subject: [PATCH 4/6] Pre-allocate query parameters for the pagination condition --- query/query.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/query/query.go b/query/query.go index 39c65b8..b1fe902 100644 --- a/query/query.go +++ b/query/query.go @@ -52,6 +52,12 @@ func (b *QueryBuilder) addPaginationArguments() error { paginationConditions := []string{} if len(b.options.Cursor) > 0 { + // Pre-allocate argument counters so that we don't need to duplicate them below + args := make([]string, 0, len(b.options.Cursor)) + for _, val := range b.options.Cursor { + args = append(args, b.pushArgument(val.Value)) + } + for i := range b.options.Cursor { subcondition := []string{} for j, from := range b.options.Cursor { @@ -67,7 +73,7 @@ func (b *QueryBuilder) addPaginationArguments() error { operator = ">" } - arg := b.pushArgument(from.Value) + arg := args[j] columnIx, err := b.options.GetColumnIndex(from.ColumnName) if err != nil { From f06afb981fae8504004d598e4f0a973358db24d0 Mon Sep 17 00:00:00 2001 From: r-vdp Date: Thu, 11 Dec 2025 16:02:26 +0100 Subject: [PATCH 5/6] Fix pagination condition --- query/query.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/query/query.go b/query/query.go index b1fe902..8319138 100644 --- a/query/query.go +++ b/query/query.go @@ -102,7 +102,9 @@ func (b *QueryBuilder) addPaginationArguments() error { b.queryBuilder.WriteString(" AND ") } + b.queryBuilder.WriteString("(") b.queryBuilder.WriteString(paginationCondition) + b.queryBuilder.WriteString(")") } return nil From c696aa88f0cdfbeaab39b151531d4b6e1a0c14b9 Mon Sep 17 00:00:00 2001 From: r-vdp Date: Thu, 11 Dec 2025 16:02:38 +0100 Subject: [PATCH 6/6] Make gopls happy --- query/query_options.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/query/query_options.go b/query/query_options.go index 8abfce4..3228681 100644 --- a/query/query_options.go +++ b/query/query_options.go @@ -10,11 +10,11 @@ import ( const QueryResultCountLimit uint64 = 200 -// 256 bytes is for the overhead of the 'envelope' around the entity data +// ResponseSize is 256 bytes for the overhead of the 'envelope' around the entity data // and the separator characters in between const ResponseSize int = 256 -// 512 kb +// MaxResponseSize is 512 kb const MaxResponseSize int = 512 * 1024 * 1024 type Column struct {