Skip to content

Commit d0fd7bd

Browse files
authored
Feature/issue 45 expose discover conns (#51)
1 parent b470d74 commit d0fd7bd

File tree

2 files changed

+135
-31
lines changed

2 files changed

+135
-31
lines changed

cmd/sling/sling_conns.go

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,143 @@ import (
1818
)
1919

2020
var (
21-
connsDiscover = func(*g.CliSC) error { return g.Error("please use the official build of Sling CLI to use this command") }
21+
connsDiscover = discoverConnection
2222
connsCheck = func(*g.CliSC) error { return g.Error("please use the official build of Sling CLI to use this command") }
2323
)
2424

25+
func discoverConnection(c *g.CliSC) error {
26+
env.SetTelVal("task", g.Marshal(g.M("type", sling.ConnDiscover)))
27+
28+
name := cast.ToString(c.Vals["name"])
29+
if name == "" {
30+
return g.Error("connection name is required")
31+
}
32+
33+
// Get connection
34+
entries := connection.GetLocalConns()
35+
conn := entries.Get(name)
36+
if conn.Name == "" {
37+
return g.Error("did not find connection %s", name)
38+
}
39+
40+
env.SetTelVal("conn_type", conn.Connection.Type.String())
41+
42+
// Parse options
43+
pattern := cast.ToString(c.Vals["pattern"])
44+
recursive := cast.ToBool(c.Vals["recursive"])
45+
showColumns := cast.ToBool(c.Vals["columns"])
46+
47+
level := database.SchemataLevelTable
48+
if showColumns {
49+
level = database.SchemataLevelColumn
50+
}
51+
52+
opt := &connection.DiscoverOptions{
53+
Pattern: pattern,
54+
Level: level,
55+
Recursive: recursive,
56+
}
57+
58+
// Discover using the robust implementation
59+
ok, nodes, schemata, err := conn.Connection.Discover(opt)
60+
if err != nil {
61+
return g.Error(err, "could not discover %s", name)
62+
}
63+
64+
if !ok {
65+
return g.Error("discovery failed for %s", name)
66+
}
67+
68+
asJSON := os.Getenv("SLING_OUTPUT") == "json"
69+
70+
// Output results
71+
if conn.Connection.Type.IsDb() {
72+
// Database connection
73+
if level == database.SchemataLevelColumn {
74+
columns := schemata.Columns()
75+
if asJSON {
76+
fmt.Println(g.Marshal(g.M("columns", columns)))
77+
} else {
78+
if len(columns) == 0 {
79+
g.Info("No columns found")
80+
return nil
81+
}
82+
fields := []string{"column_name", "data_type", "table_name", "schema_name"}
83+
rows := make([][]interface{}, 0, len(columns))
84+
for _, col := range columns {
85+
rows = append(rows, []interface{}{col.Name, col.Type, col.Table, col.Schema})
86+
}
87+
fmt.Println(g.PrettyTable(fields, rows))
88+
}
89+
} else {
90+
tables := schemata.Tables()
91+
if asJSON {
92+
fmt.Println(g.Marshal(g.M("tables", tables)))
93+
} else {
94+
if len(tables) == 0 {
95+
g.Info("No tables found")
96+
return nil
97+
}
98+
99+
// Match official output format with row numbers and database column
100+
fields := []string{"#", "database", "schema", "name", "type"}
101+
rows := make([][]interface{}, 0, len(tables))
102+
rowNum := 1
103+
for _, table := range tables {
104+
tableType := "table"
105+
if table.IsView {
106+
tableType = "view"
107+
}
108+
database := table.Database
109+
if database == "" {
110+
database = "default" // Default for databases that don't specify
111+
}
112+
rows = append(rows, []interface{}{rowNum, database, table.Schema, table.Name, tableType})
113+
rowNum++
114+
}
115+
fmt.Println(g.PrettyTable(fields, rows))
116+
}
117+
}
118+
} else {
119+
// File connection
120+
if asJSON {
121+
fmt.Println(g.Marshal(g.M("files", nodes)))
122+
} else {
123+
if len(nodes) == 0 {
124+
g.Info("No files found")
125+
return nil
126+
}
127+
128+
if showColumns {
129+
// Show files with their columns
130+
for _, node := range nodes {
131+
fmt.Printf("\nFile: %s\n", node.Path())
132+
if len(node.Columns) > 0 {
133+
fields := []string{"column_name", "data_type"}
134+
rows := make([][]interface{}, 0, len(node.Columns))
135+
for _, col := range node.Columns {
136+
rows = append(rows, []interface{}{col.Name, col.Type})
137+
}
138+
fmt.Println(g.PrettyTable(fields, rows))
139+
} else {
140+
fmt.Println(" No column information available")
141+
}
142+
}
143+
} else {
144+
// Show just file paths
145+
fields := []string{"file_path", "size", "type"}
146+
rows := make([][]interface{}, 0, len(nodes))
147+
for _, node := range nodes {
148+
rows = append(rows, []interface{}{node.Path(), node.Size, node.Type})
149+
}
150+
fmt.Println(g.PrettyTable(fields, rows))
151+
}
152+
}
153+
}
154+
155+
return nil
156+
}
157+
25158
func processConns(c *g.CliSC) (ok bool, err error) {
26159
ok = true
27160

core/dbio/connection/connection_discover.go

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package connection
22

33
import (
44
"context"
5-
"sort"
65
"strings"
76
"time"
87

@@ -12,8 +11,6 @@ import (
1211
"github.com/slingdata-io/sling-cli/core/dbio/database"
1312
"github.com/slingdata-io/sling-cli/core/dbio/filesys"
1413
"github.com/slingdata-io/sling-cli/core/dbio/iop"
15-
"github.com/slingdata-io/sling-cli/core/env"
16-
"github.com/spf13/cast"
1714
)
1815

1916
func (c *Connection) Test() (ok bool, err error) {
@@ -177,7 +174,7 @@ func (c *Connection) Discover(opt *DiscoverOptions) (ok bool, nodes filesys.File
177174
return ok, nodes, schemata, g.Error(err, "could not connect to %s", c.Name)
178175
}
179176
g.Debug("unfiltered nodes returned: %d", len(nodes))
180-
if len(nodes) <= 10 {
177+
if len(nodes) <= 20 {
181178
g.Debug(g.Marshal(nodes.Paths()))
182179
}
183180

@@ -244,29 +241,3 @@ func (c *Connection) Discover(opt *DiscoverOptions) (ok bool, nodes filesys.File
244241

245242
return
246243
}
247-
248-
func EnvFileConnectionEntries(ef env.EnvFile, sourceName string) (entries ConnEntries, err error) {
249-
m := g.M()
250-
if err = g.JSONConvert(ef, &m); err != nil {
251-
return entries, g.Error(err)
252-
}
253-
254-
connsMap := map[string]ConnEntry{}
255-
profileConns, err := ReadConnections(m)
256-
for _, conn := range profileConns {
257-
c := ConnEntry{
258-
Name: strings.ToUpper(conn.Info().Name),
259-
Description: conn.Type.NameLong(),
260-
Source: sourceName,
261-
Connection: conn,
262-
}
263-
connsMap[c.Name] = c
264-
}
265-
266-
entries = lo.Values(connsMap)
267-
sort.Slice(entries, func(i, j int) bool {
268-
return cast.ToString(entries[i].Name) < cast.ToString(entries[j].Name)
269-
})
270-
271-
return
272-
}

0 commit comments

Comments
 (0)