diff --git a/db/queries/queries.sql b/db/queries/queries.sql index e2a1615..9112485 100644 --- a/db/queries/queries.sql +++ b/db/queries/queries.sql @@ -846,12 +846,13 @@ LIMIT $4; -- name: SearchKnownRoutes :many -- Returns known routes containing a subsequence from source to destination hash prefix. --- Matches routes where source hash appears before destination hash in the hash_prefix array. +-- Verifies source appears before destination in the route. SELECT id, node_ids, hash_prefix, iata, hop_count, first_seen, last_seen FROM known_routes WHERE iata = $1 - AND hash_prefix @> ARRAY[$2::bytea] - AND hash_prefix @> ARRAY[$3::bytea] + AND array_position(hash_prefix, $2::bytea) IS NOT NULL + AND array_position(hash_prefix, $3::bytea) IS NOT NULL + AND array_position(hash_prefix, $2::bytea) < array_position(hash_prefix, $3::bytea) ORDER BY hop_count ASC, last_seen DESC; -- ============================================================ diff --git a/db/routes.go b/db/routes.go index e2be41e..4463ca1 100644 --- a/db/routes.go +++ b/db/routes.go @@ -48,7 +48,42 @@ func (s *Store) SearchKnownRoutes(ctx context.Context, iata, fromHash, toHash st if err != nil { return nil, err } - return toKnownRoutes(rows), nil + items := make([]api.KnownRoute, 0, len(rows)) + for _, r := range rows { + // find positions and slice to the subsequence + fromPos, toPos := -1, -1 + for i, h := range r.HashPrefix { + if fromPos == -1 && hex.EncodeToString(h) == fromHash { + fromPos = i + } + if fromPos != -1 && hex.EncodeToString(h) == toHash { + toPos = i + break + } + } + if fromPos == -1 || toPos == -1 { + continue + } + nodeIDs := r.NodeIds[fromPos : toPos+1] + hashPrefix := r.HashPrefix[fromPos : toPos+1] + hops := make([]api.RouteHop, 0, len(nodeIDs)) + for i, nodeID := range nodeIDs { + hop := api.RouteHop{NodeID: nodeID} + if i < len(hashPrefix) { + hop.HashBytes = hex.EncodeToString(hashPrefix[i]) + } + hops = append(hops, hop) + } + items = append(items, api.KnownRoute{ + ID: r.ID, + IATA: r.Iata, + HopCount: int32(len(hops)), + Hops: hops, + FirstSeen: r.FirstSeen.Time.UnixMilli(), + LastSeen: r.LastSeen.Time.UnixMilli(), + }) + } + return items, nil } func toKnownRoutes(rows []sqlc.KnownRoute) []api.KnownRoute { diff --git a/db/sqlc/queries.sql.go b/db/sqlc/queries.sql.go index 2600845..a88e0b8 100644 --- a/db/sqlc/queries.sql.go +++ b/db/sqlc/queries.sql.go @@ -2705,8 +2705,9 @@ const searchKnownRoutes = `-- name: SearchKnownRoutes :many SELECT id, node_ids, hash_prefix, iata, hop_count, first_seen, last_seen FROM known_routes WHERE iata = $1 - AND hash_prefix @> ARRAY[$2::bytea] - AND hash_prefix @> ARRAY[$3::bytea] + AND array_position(hash_prefix, $2::bytea) IS NOT NULL + AND array_position(hash_prefix, $3::bytea) IS NOT NULL + AND array_position(hash_prefix, $2::bytea) < array_position(hash_prefix, $3::bytea) ORDER BY hop_count ASC, last_seen DESC ` @@ -2717,7 +2718,7 @@ type SearchKnownRoutesParams struct { } // Returns known routes containing a subsequence from source to destination hash prefix. -// Matches routes where source hash appears before destination hash in the hash_prefix array. +// Verifies source appears before destination in the route. func (q *Queries) SearchKnownRoutes(ctx context.Context, arg SearchKnownRoutesParams) ([]KnownRoute, error) { rows, err := q.db.Query(ctx, searchKnownRoutes, arg.Iata, arg.Column2, arg.Column3) if err != nil {