11package cmd
22
33import (
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+
1216var (
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
4244By 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+
152230func runQueryGraph (cmd * cobra.Command , args []string ) error {
153231 queryCode := strings .TrimSpace (args [0 ])
154232 if queryCode == "" {
0 commit comments