Skip to content

Commit 4defdda

Browse files
buty4649claude
andauthored
query: exec を全件取得へ変更し --rows / --offset を撤廃 (#43)
list 型クエリの実行結果を rows=1000 で自動ページングし、 exec_result.data が空または短いページになった時点でループ終了する ように変更。--no-run 指定時はページング不要なので従来通り1回の リクエストで定義のみを取得する。 Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent c81dc3d commit 4defdda

File tree

1 file changed

+96
-18
lines changed

1 file changed

+96
-18
lines changed

cmd/query.go

Lines changed: 96 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package cmd
22

33
import (
4+
"context"
5+
"encoding/json"
46
"fmt"
57
"os"
68
"strings"
@@ -9,14 +11,14 @@ import (
911
"github.com/spf13/cobra"
1012
)
1113

14+
const queryExecPageSize = 1000
15+
1216
var (
1317
queryListOutput string
1418
queryListJQ string
1519

16-
queryExecNoRun bool
17-
queryExecRows int
18-
queryExecOffset int
19-
queryExecJQ string
20+
queryExecNoRun bool
21+
queryExecJQ string
2022

2123
queryGraphFormat string
2224
queryGraphOutput string
@@ -40,8 +42,9 @@ var queryExecCmd = &cobra.Command{
4042
Long: `Fetch a query and its execution result via GET /api/v1/query/{query_code}.
4143
4244
By default the query is executed (exec_flg=true) and the response contains
43-
both the definition and exec_result. Pass --no-run to fetch the definition
44-
only. --rows (default 500) and --offset control pagination for list queries.`,
45+
both the definition and exec_result. List-type queries are paged through
46+
automatically (rows=1000) until exec_result.data is exhausted. Pass
47+
--no-run to fetch the definition only.`,
4548
Args: cobra.ExactArgs(1),
4649
RunE: runQueryExec,
4750
}
@@ -73,8 +76,6 @@ func init() {
7376

7477
ef := queryExecCmd.Flags()
7578
ef.BoolVar(&queryExecNoRun, "no-run", false, "do not execute the query; return the definition only (exec_flg=false)")
76-
ef.IntVar(&queryExecRows, "rows", 0, "max rows returned by list queries (0 = omit; server default 500; range 1-10000)")
77-
ef.IntVar(&queryExecOffset, "offset", 0, "offset for list queries (0 = omit)")
7879
ef.StringVar(&queryExecJQ, "jq", "", "apply a gojq filter to the JSON response")
7980

8081
gf := queryGraphCmd.Flags()
@@ -129,17 +130,13 @@ func runQueryExec(cmd *cobra.Command, args []string) error {
129130
if err != nil {
130131
return err
131132
}
132-
p := xpoint.GetQueryParams{ExecFlag: !queryExecNoRun}
133-
if cmd.Flags().Changed("rows") {
134-
v := queryExecRows
135-
p.Rows = &v
136-
}
137-
if cmd.Flags().Changed("offset") {
138-
v := queryExecOffset
139-
p.Offset = &v
140-
}
141133

142-
raw, err := client.GetQuery(cmd.Context(), queryCode, p)
134+
var raw json.RawMessage
135+
if queryExecNoRun {
136+
raw, err = client.GetQuery(cmd.Context(), queryCode, xpoint.GetQueryParams{ExecFlag: false})
137+
} else {
138+
raw, err = fetchAllQueryExec(cmd.Context(), client, queryCode)
139+
}
143140
if err != nil {
144141
return err
145142
}
@@ -149,6 +146,87 @@ func runQueryExec(cmd *cobra.Command, args []string) error {
149146
return writeJSON(os.Stdout, raw)
150147
}
151148

149+
// fetchAllQueryExec runs a query with exec_flg=true and pages through
150+
// exec_result.data (rows=1000) until the server reports an empty or missing
151+
// data array. For non-list queries whose exec_result does not contain a data
152+
// array, the first response is returned as-is.
153+
func fetchAllQueryExec(ctx context.Context, client *xpoint.Client, queryCode string) (json.RawMessage, error) {
154+
rows := queryExecPageSize
155+
offset := 0
156+
p := xpoint.GetQueryParams{ExecFlag: true, Rows: &rows, Offset: &offset}
157+
158+
var (
159+
firstEnv map[string]json.RawMessage
160+
allData []json.RawMessage
161+
)
162+
163+
for {
164+
p.Offset = &offset
165+
raw, err := client.GetQuery(ctx, queryCode, p)
166+
if err != nil {
167+
return nil, err
168+
}
169+
var env map[string]json.RawMessage
170+
if err := json.Unmarshal(raw, &env); err != nil {
171+
return nil, fmt.Errorf("parse query response: %w", err)
172+
}
173+
if offset == 0 {
174+
firstEnv = env
175+
}
176+
177+
execRaw, ok := env["exec_result"]
178+
if !ok {
179+
break
180+
}
181+
var execResult map[string]json.RawMessage
182+
if err := json.Unmarshal(execRaw, &execResult); err != nil {
183+
break
184+
}
185+
dataRaw, ok := execResult["data"]
186+
if !ok {
187+
break
188+
}
189+
var data []json.RawMessage
190+
if err := json.Unmarshal(dataRaw, &data); err != nil {
191+
break
192+
}
193+
if len(data) == 0 {
194+
break
195+
}
196+
allData = append(allData, data...)
197+
if len(data) < queryExecPageSize {
198+
break
199+
}
200+
offset += queryExecPageSize
201+
}
202+
203+
if firstEnv == nil {
204+
return nil, fmt.Errorf("empty response")
205+
}
206+
if len(allData) == 0 {
207+
return json.Marshal(firstEnv)
208+
}
209+
210+
var execResult map[string]json.RawMessage
211+
if raw, ok := firstEnv["exec_result"]; ok {
212+
_ = json.Unmarshal(raw, &execResult)
213+
}
214+
if execResult == nil {
215+
execResult = map[string]json.RawMessage{}
216+
}
217+
encoded, err := json.Marshal(allData)
218+
if err != nil {
219+
return nil, err
220+
}
221+
execResult["data"] = encoded
222+
mergedExec, err := json.Marshal(execResult)
223+
if err != nil {
224+
return nil, err
225+
}
226+
firstEnv["exec_result"] = mergedExec
227+
return json.Marshal(firstEnv)
228+
}
229+
152230
func runQueryGraph(cmd *cobra.Command, args []string) error {
153231
queryCode := strings.TrimSpace(args[0])
154232
if queryCode == "" {

0 commit comments

Comments
 (0)