mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-09-02 00:58:22 +00:00
add region filter to nodes
This commit is contained in:
@@ -348,7 +348,7 @@ FROM nodes n
|
||||
LEFT JOIN node_iatas ni ON ni.node_id = n.id
|
||||
WHERE
|
||||
($1 = 0 OR n.node_type = $1)
|
||||
AND ($2 = '' OR n.id IN (SELECT node_id FROM node_iatas WHERE iata ILIKE $2))
|
||||
AND ($2::text = '' OR n.id IN (SELECT node_id FROM node_iatas WHERE iata = ANY(string_to_array($2::text, ','))))
|
||||
AND (
|
||||
$3::text = 'any'
|
||||
OR ($3::text = 'true' AND n.supports_multibyte_paths = TRUE)
|
||||
|
||||
@@ -1439,7 +1439,7 @@ FROM nodes n
|
||||
LEFT JOIN node_iatas ni ON ni.node_id = n.id
|
||||
WHERE
|
||||
($1 = 0 OR n.node_type = $1)
|
||||
AND ($2 = '' OR n.id IN (SELECT node_id FROM node_iatas WHERE iata ILIKE $2))
|
||||
AND ($2::text = '' OR n.id IN (SELECT node_id FROM node_iatas WHERE iata = ANY(string_to_array($2::text, ','))))
|
||||
AND (
|
||||
$3::text = 'any'
|
||||
OR ($3::text = 'true' AND n.supports_multibyte_paths = TRUE)
|
||||
@@ -1460,7 +1460,7 @@ LIMIT $8
|
||||
|
||||
type ListNodesParams struct {
|
||||
Column1 interface{} `json:"column_1"`
|
||||
Column2 interface{} `json:"column_2"`
|
||||
Column2 string `json:"column_2"`
|
||||
Column3 string `json:"column_3"`
|
||||
Column4 string `json:"column_4"`
|
||||
Column5 []byte `json:"column_5"`
|
||||
|
||||
+3
-2
@@ -876,14 +876,15 @@ func (s *Store) ListObserverAdverts(ctx context.Context, observerID uuid.UUID, c
|
||||
// ListNodes returns a paginated list of nodes with optional filters.
|
||||
// Pass 0 for nodeType, empty string for iata/name, nil for pubkey to skip those filters.
|
||||
// cursor is last_seen epoch ms; pass 0 to start from the beginning.
|
||||
func (s *Store) ListNodes(ctx context.Context, nodeType int16, iata string, supportsMultibytePaths, supportsMultibyteTraces *bool, pubkey []byte, name string, cursor int64, limit int32) (api.Page[api.NodeSummary], error) {
|
||||
func (s *Store) ListNodes(ctx context.Context, nodeType int16, iatas []string, supportsMultibytePaths, supportsMultibyteTraces *bool, pubkey []byte, name string, cursor int64, limit int32) (api.Page[api.NodeSummary], error) {
|
||||
var cursorTS pgtype.Timestamptz
|
||||
if cursor > 0 {
|
||||
cursorTS = pgtype.Timestamptz{Time: time.UnixMilli(cursor), Valid: true}
|
||||
}
|
||||
iataFilter := strings.Join(iatas, ",")
|
||||
rows, err := s.q.ListNodes(ctx, sqlc.ListNodesParams{
|
||||
Column1: nodeType,
|
||||
Column2: iata,
|
||||
Column2: iataFilter,
|
||||
Column3: tristate(supportsMultibytePaths),
|
||||
Column4: tristate(supportsMultibyteTraces),
|
||||
Column5: pubkey,
|
||||
|
||||
+19
-1
@@ -360,10 +360,28 @@ const docTemplate = `{
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by IATA code (case-insensitive)",
|
||||
"description": "Filter by single IATA code (case-insensitive)",
|
||||
"name": "iata",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by multiple IATA codes, comma-separated e.g. YVR,YYJ",
|
||||
"name": "iatas",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Filter by region ID, expands to member IATAs",
|
||||
"name": "regionId",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by region slug, expands to member IATAs",
|
||||
"name": "region",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Partial case-insensitive name match",
|
||||
|
||||
+19
-1
@@ -358,10 +358,28 @@
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by IATA code (case-insensitive)",
|
||||
"description": "Filter by single IATA code (case-insensitive)",
|
||||
"name": "iata",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by multiple IATA codes, comma-separated e.g. YVR,YYJ",
|
||||
"name": "iatas",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Filter by region ID, expands to member IATAs",
|
||||
"name": "regionId",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by region slug, expands to member IATAs",
|
||||
"name": "region",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Partial case-insensitive name match",
|
||||
|
||||
+13
-1
@@ -908,10 +908,22 @@ paths:
|
||||
in: query
|
||||
name: typeName
|
||||
type: string
|
||||
- description: Filter by IATA code (case-insensitive)
|
||||
- description: Filter by single IATA code (case-insensitive)
|
||||
in: query
|
||||
name: iata
|
||||
type: string
|
||||
- description: Filter by multiple IATA codes, comma-separated e.g. YVR,YYJ
|
||||
in: query
|
||||
name: iatas
|
||||
type: string
|
||||
- description: Filter by region ID, expands to member IATAs
|
||||
in: query
|
||||
name: regionId
|
||||
type: integer
|
||||
- description: Filter by region slug, expands to member IATAs
|
||||
in: query
|
||||
name: region
|
||||
type: string
|
||||
- description: Partial case-insensitive name match
|
||||
in: query
|
||||
name: name
|
||||
|
||||
@@ -32,7 +32,10 @@ func NodesRouter(reader api.Reader) http.Handler {
|
||||
// @Produce json
|
||||
// @Param type query int false "Node type integer (1=companion, 2=repeater, 3=room_server, 4=sensor)"
|
||||
// @Param typeName query string false "Node type name (companion, repeater, room_server, sensor)"
|
||||
// @Param iata query string false "Filter by IATA code (case-insensitive)"
|
||||
// @Param iata query string false "Filter by single IATA code (case-insensitive)"
|
||||
// @Param iatas query string false "Filter by multiple IATA codes, comma-separated e.g. YVR,YYJ"
|
||||
// @Param regionId query int false "Filter by region ID, expands to member IATAs"
|
||||
// @Param region query string false "Filter by region slug, expands to member IATAs"
|
||||
// @Param name query string false "Partial case-insensitive name match"
|
||||
// @Param pubkey query string false "Exact public key match (hex)"
|
||||
// @Param supportsMultibytePaths query bool false "Filter by multibyte path support (true/false); omit for no filter"
|
||||
@@ -83,7 +86,15 @@ func listNodes(reader api.Reader) http.HandlerFunc {
|
||||
}
|
||||
pubkey = b
|
||||
}
|
||||
iata := r.URL.Query().Get("iata")
|
||||
iatas := parseIATAs(r)
|
||||
if regionIDStr := r.URL.Query().Get("regionId"); regionIDStr != "" || r.URL.Query().Get("region") != "" {
|
||||
regionIATAs, err := resolveRegionIATAs(r.Context(), regionIDStr, r.URL.Query().Get("region"), reader)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
iatas = append(iatas, regionIATAs...)
|
||||
}
|
||||
name := r.URL.Query().Get("name")
|
||||
var supportsMultibytePaths *bool
|
||||
if v := r.URL.Query().Get("supportsMultibytePaths"); v != "" {
|
||||
@@ -103,7 +114,7 @@ func listNodes(reader api.Reader) http.HandlerFunc {
|
||||
}
|
||||
supportsMultibyteTraces = &b
|
||||
}
|
||||
nodes, err := reader.ListNodes(r.Context(), nodeType, iata, supportsMultibytePaths, supportsMultibyteTraces, pubkey, name, cursor, limit)
|
||||
nodes, err := reader.ListNodes(r.Context(), nodeType, iatas, supportsMultibytePaths, supportsMultibyteTraces, pubkey, name, cursor, limit)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "internal server error")
|
||||
return
|
||||
|
||||
@@ -412,9 +412,9 @@ type Reader interface {
|
||||
// Pass cursor=0 to start from the beginning.
|
||||
ListObserverAdverts(ctx context.Context, observerID uuid.UUID, cursor int64, limit int32) (Page[AdvertObservation], error)
|
||||
// ListNodes returns a paginated list of nodes with optional filters.
|
||||
// Pass 0 for nodeType, empty string for iata, nil for pubkey to skip those filters.
|
||||
// Pass 0 for nodeType, nil iatas, nil for pubkey to skip those filters.
|
||||
// cursor is last_seen epoch ms; pass 0 to start from the beginning.
|
||||
ListNodes(ctx context.Context, nodeType int16, iata string, supportsMultibytePaths, supportsMultibyteTraces *bool, pubkey []byte, name string, cursor int64, limit int32) (Page[NodeSummary], error)
|
||||
ListNodes(ctx context.Context, nodeType int16, iatas []string, supportsMultibytePaths, supportsMultibyteTraces *bool, pubkey []byte, name string, cursor int64, limit int32) (Page[NodeSummary], error)
|
||||
|
||||
// GetNode returns full detail for a single node by UUID.
|
||||
// Returns nil, pgx.ErrNoRows if the node is not found.
|
||||
|
||||
Reference in New Issue
Block a user