@@ -2,15 +2,29 @@ package auth
22
33import (
44 "bufio"
5+ "errors"
56 "fmt"
67 "os"
78 "strings"
9+ "time"
810
911 "github.com/duneanalytics/cli/authconfig"
12+ "github.com/duneanalytics/cli/output"
13+ "github.com/duneanalytics/duneapi-client-go/config"
14+ "github.com/duneanalytics/duneapi-client-go/dune"
15+ "github.com/duneanalytics/duneapi-client-go/models"
1016 "github.com/spf13/cobra"
1117 "golang.org/x/term"
1218)
1319
20+ const (
21+ queryStateCompleted = "QUERY_STATE_COMPLETED"
22+
23+ // sampleQueryMaxRetries is the error-retry ceiling for the sample query poll loop.
24+ // Matches the CLI default: 300s timeout / 2s poll interval = 150.
25+ sampleQueryMaxRetries = 150
26+ )
27+
1428// NewAuthCmd returns the `auth` command.
1529func NewAuthCmd () * cobra.Command {
1630 return & cobra.Command {
@@ -29,20 +43,20 @@ func runAuth(cmd *cobra.Command, _ []string) error {
2943 key = os .Getenv ("DUNE_API_KEY" )
3044 }
3145
46+ // stdinReader is shared across all interactive prompts so a single
47+ // buffered reader is used for the underlying stream.
48+ var stdinReader * bufio.Reader
49+
3250 if key == "" {
3351 if stdin , ok := cmd .InOrStdin ().(* os.File ); ok && ! term .IsTerminal (int (stdin .Fd ())) {
3452 return fmt .Errorf ("no API key provided; pass --api-key, set DUNE_API_KEY, or run dune auth in an interactive terminal" )
3553 }
3654
37- var (
38- reader = cmd .InOrStdin ()
39- )
55+ stdinReader = bufio .NewReader (cmd .InOrStdin ())
4056
4157 fmt .Fprint (cmd .ErrOrStderr (), "Enter your Dune API key: " )
42- scanner := bufio .NewScanner (reader )
43- if scanner .Scan () {
44- key = strings .TrimSpace (scanner .Text ())
45- }
58+ line , _ := stdinReader .ReadString ('\n' )
59+ key = strings .TrimSpace (line )
4660 }
4761
4862 if key == "" {
@@ -63,5 +77,65 @@ func runAuth(cmd *cobra.Command, _ []string) error {
6377
6478 p , _ := authconfig .Path ()
6579 fmt .Fprintf (cmd .OutOrStdout (), "API key saved to %s\n " , p )
80+
81+ if err := maybeSampleQuery (cmd , key , stdinReader ); err != nil {
82+ fmt .Fprintf (cmd .ErrOrStderr (), "Sample query failed: %v\n " , err )
83+ }
84+
85+ return nil
86+ }
87+
88+ const sampleSQL = "SELECT number, time, gas_used, base_fee_per_gas FROM ethereum.blocks ORDER BY number DESC LIMIT 5"
89+
90+ func maybeSampleQuery (cmd * cobra.Command , apiKey string , reader * bufio.Reader ) error {
91+ // Only prompt in interactive terminals.
92+ if reader == nil {
93+ // Non-interactive path (key was provided via flag or env var).
94+ // Create a reader to check for a terminal; if not interactive, skip.
95+ stdin , ok := cmd .InOrStdin ().(* os.File )
96+ if ! ok || ! term .IsTerminal (int (stdin .Fd ())) {
97+ return nil
98+ }
99+ reader = bufio .NewReader (cmd .InOrStdin ())
100+ }
101+
102+ fmt .Fprint (cmd .ErrOrStderr (), "\n Would you like to run a sample query to verify your setup? [Y/n] " )
103+ line , _ := reader .ReadString ('\n' )
104+ answer := strings .TrimSpace (strings .ToLower (line ))
105+ if answer != "" && answer != "y" && answer != "yes" {
106+ return nil
107+ }
108+
109+ fmt .Fprintf (cmd .ErrOrStderr (), "\n Running: %s\n \n " , sampleSQL )
110+
111+ client := dune .NewDuneClient (config .FromAPIKey (apiKey ))
112+ exec , err := client .RunSQL (models.ExecuteSQLRequest {
113+ SQL : sampleSQL ,
114+ Performance : "medium" ,
115+ })
116+ if err != nil {
117+ return fmt .Errorf ("executing query: %w" , err )
118+ }
119+
120+ resp , err := exec .WaitGetResults (2 * time .Second , sampleQueryMaxRetries )
121+ if err != nil {
122+ return fmt .Errorf ("waiting for results: %w" , err )
123+ }
124+
125+ if resp .State != queryStateCompleted {
126+ msg := fmt .Sprintf ("query finished with state %s" , resp .State )
127+ if resp .Error != nil {
128+ msg += fmt .Sprintf (": %s" , resp .Error .Message )
129+ }
130+ return errors .New (msg )
131+ }
132+
133+ w := cmd .OutOrStdout ()
134+ columns := resp .Result .Metadata .ColumnNames
135+ rows := output .ResultRowsToStrings (resp .Result .Rows , columns )
136+ output .PrintTable (w , columns , rows )
137+ fmt .Fprintf (w , "\n %d rows\n " , len (resp .Result .Rows ))
138+ fmt .Fprintln (w , "\n You're all set! Run `dune query run-sql --sql \" YOUR SQL\" ` to execute your own queries." )
139+
66140 return nil
67141}
0 commit comments