diff --git a/cli/cli.go b/cli/cli.go index b2b9ddb5..4e86b962 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -348,6 +348,8 @@ func (rc *RunContext) preRunE() error { } rc.wrtr = newWriters(rc.Log, rc.Cmd, rc.Config.Options, rc.Out, rc.ErrOut) + rc.Out = rc.wrtr.out + rc.ErrOut = rc.wrtr.errOut var scratchSrcFunc driver.ScratchSrcFunc @@ -456,6 +458,8 @@ func (rc *RunContext) databases() *driver.Databases { // writers is a container for the various output writer types. type writers struct { + out io.Writer + errOut io.Writer fmt *output.Formatting recordw output.RecordWriter metaw output.MetadataWriter @@ -491,6 +495,8 @@ func newWriters(log lg.Log, cmd *cobra.Command, opts config.Options, out, errOut // flags and set the various writer fields depending upon which // writers the format implements. w := &writers{ + out: out, + errOut: errOut, fmt: fm, recordw: tablew.NewRecordWriter(out, fm, hasHeader), metaw: tablew.NewMetadataWriter(out, fm), diff --git a/cli/cmd_add.go b/cli/cmd_add.go index 0e2795c9..1550d7b7 100644 --- a/cli/cmd_add.go +++ b/cli/cmd_add.go @@ -149,8 +149,8 @@ func execSrcAdd(rc *RunContext, cmd *cobra.Command, args []string) error { // // The second form is particularly nice for bash completion etc. if typ == sqlite3.Type { - if !strings.HasPrefix(loc, "sqlite3:") { - loc = "sqlite3:" + loc + if !strings.HasPrefix(loc, sqlite3.Prefix) { + loc = sqlite3.Prefix + loc } } diff --git a/cli/cmd_notify.go b/cli/cmd_notify.go index f8c9f608..03dc829d 100644 --- a/cli/cmd_notify.go +++ b/cli/cmd_notify.go @@ -181,8 +181,8 @@ func newNotifyAddHipChatCmd() (*cobra.Command, runFunc) { } func execNotifyAddHipChat(rc *RunContext, cmd *cobra.Command, args []string) error { - fmt.Println("Add HipChat room") - fmt.Println(strings.Join(args, " | ")) + fmt.Fprintln(rc.Out, "Add HipChat room") + fmt.Fprintln(rc.Out, strings.Join(args, " | ")) var label string var err error @@ -194,7 +194,7 @@ func execNotifyAddHipChat(rc *RunContext, cmd *cobra.Command, args []string) err } if label != "" { - fmt.Printf("Label: %s", label) + fmt.Fprintf(rc.Out, "Label: %s", label) } return nil diff --git a/cli/cmd_slq_test.go b/cli/cmd_slq_test.go index f8d28310..5f71b9c6 100644 --- a/cli/cmd_slq_test.go +++ b/cli/cmd_slq_test.go @@ -18,24 +18,15 @@ import ( "github.com/neilotoole/sq/testh/sakila" ) -func TestCmdSLQ_Insert_LONG(t *testing.T) { - testh.SkipShort(t, true) - testCmdSLQ_Insert(t, sakila.All, sakila.SQLAll) -} - +// TestCmdSLQ_Insert tests "sq slq QUERY --insert=dest.tbl". func TestCmdSLQ_Insert(t *testing.T) { - testCmdSLQ_Insert(t, sakila.SQLLatest, sakila.SQLLatest) -} - -// testCmdSLQ_Insert tests "sq slq QUERY --insert=dest.tbl". -func testCmdSLQ_Insert(t *testing.T, origins, dests []string) { - for _, origin := range origins { + for _, origin := range sakila.SQLLatest { origin := origin t.Run("origin_"+origin, func(t *testing.T) { testh.SkipShort(t, origin == sakila.XLSX) - for _, dest := range dests { + for _, dest := range sakila.SQLLatest { dest := dest t.Run("dest_"+dest, func(t *testing.T) { diff --git a/cli/cmd_sql_test.go b/cli/cmd_sql_test.go index 7ece29d1..82224bdb 100644 --- a/cli/cmd_sql_test.go +++ b/cli/cmd_sql_test.go @@ -16,23 +16,15 @@ import ( "github.com/neilotoole/sq/testh/testsrc" ) -func TestCmdSQL_Insert_LONG(t *testing.T) { - testh.SkipShort(t, true) - testCmdSQL_Insert(t, sakila.All, sakila.All) -} +// TestCmdSQL_Insert tests "sq sql QUERY --insert=dest.tbl". func TestCmdSQL_Insert(t *testing.T) { - testCmdSQL_Insert(t, sakila.SQLLatest, sakila.SQLLatest) -} - -// testCmdSQL_Insert tests "sq sql QUERY --insert=dest.tbl". -func testCmdSQL_Insert(t *testing.T, origins, dests []string) { - for _, origin := range origins { + for _, origin := range sakila.SQLLatest { origin := origin t.Run("origin_"+origin, func(t *testing.T) { testh.SkipShort(t, origin == sakila.XLSX) - for _, dest := range dests { + for _, dest := range sakila.SQLLatest { dest := dest t.Run("dest_"+dest, func(t *testing.T) { @@ -125,8 +117,8 @@ func TestCmdSQL_StdinQuery(t *testing.T) { wantCount int wantErr bool }{ - {fpath: proj.Abs(sakila.PathCSVActor), tbl: source.MonotableName, wantCount: sakila.TblActorCount + 1}, // +1 is for the header row - {fpath: proj.Abs(sakila.PathXLSXSubset), tbl: sakila.TblActor, wantCount: sakila.TblActorCount + 1}, + {fpath: proj.Abs(sakila.PathCSVActorNoHeader), tbl: source.MonotableName, wantCount: sakila.TblActorCount}, + {fpath: proj.Abs(sakila.PathXLSXSubset), tbl: sakila.TblActor, wantCount: sakila.TblActorCount + 1}, // +1 is for the header row in the XLSX file {fpath: proj.Abs("README.md"), wantErr: true}, } @@ -140,9 +132,10 @@ func TestCmdSQL_StdinQuery(t *testing.T) { require.NoError(t, err) ru := newRun(t).hush() + //ru := newRun(t) ru.rc.Stdin = f - err = ru.exec("sql", "SELECT * FROM "+tc.tbl) + err = ru.exec("sql", "--no-header", "SELECT * FROM "+tc.tbl) if tc.wantErr { require.Error(t, err) return diff --git a/cli/cmd_version.go b/cli/cmd_version.go index d5848ffa..5de7422d 100644 --- a/cli/cmd_version.go +++ b/cli/cmd_version.go @@ -23,19 +23,19 @@ func execVersion(rc *RunContext, cmd *cobra.Command, args []string) error { // If buildinfo.Version is not set (building without ldflags), // then we set a dummy version. if version == "" { - version = "0.0.0.dev" + version = "0.0.0-dev" } rc.wrtr.fmt.Hilite.Fprintf(rc.Out, "sq %s", version) if len(buildinfo.Commit) > 0 { - fmt.Fprintf(rc.Out, " ") - rc.wrtr.fmt.Faint.Fprintf(rc.Out, "#"+buildinfo.Commit) + fmt.Fprint(rc.Out, " ") + rc.wrtr.fmt.Faint.Fprint(rc.Out, "#"+buildinfo.Commit) } if len(buildinfo.Timestamp) > 0 { - fmt.Fprintf(rc.Out, " ") - rc.wrtr.fmt.Faint.Fprintf(rc.Out, buildinfo.Timestamp) + fmt.Fprint(rc.Out, " ") + rc.wrtr.fmt.Faint.Fprint(rc.Out, buildinfo.Timestamp) } fmt.Fprintln(rc.Out) diff --git a/cli/output/tablew/internal/texttable.go b/cli/output/tablew/internal/texttable.go index 9bdc9e3a..62732833 100644 --- a/cli/output/tablew/internal/texttable.go +++ b/cli/output/tablew/internal/texttable.go @@ -349,7 +349,7 @@ func (t *Table) printHeading() { pad := ConditionString(i == end && !t.borders.Left, Space, t.pColumn) head := t.headerTrans(fmt.Sprintf("%s %s ", padFunc(h, Space, v), pad)) - fmt.Print(head) + fmt.Fprint(t.out, head) } // Next line diff --git a/drivers/sqlite3/database.go b/drivers/sqlite3/database.go index 13b90a3c..7b602890 100644 --- a/drivers/sqlite3/database.go +++ b/drivers/sqlite3/database.go @@ -46,7 +46,7 @@ func (d *database) SourceMetadata(ctx context.Context) (*source.Metadata, error) meta := &source.Metadata{Handle: d.src.Handle, SourceType: Type, DBDriverType: dbDrvr} - dsn, err := PathFromSourceLocation(d.src) + dsn, err := PathFromLocation(d.src) if err != nil { return nil, err } diff --git a/drivers/sqlite3/sqlite3.go b/drivers/sqlite3/sqlite3.go index 1da515a0..a551b147 100644 --- a/drivers/sqlite3/sqlite3.go +++ b/drivers/sqlite3/sqlite3.go @@ -28,6 +28,9 @@ const ( // dbDrvr is the backing sqlite3 SQL driver impl name. dbDrvr = "sqlite3" + + // Prefix is the scheme+separator value "sqlite3://". + Prefix = "sqlite3://" ) // Provider is the SQLite3 implementation of driver.Provider. @@ -63,7 +66,7 @@ func (d *Driver) DriverMetadata() driver.Metadata { func (d *Driver) Open(ctx context.Context, src *source.Source) (driver.Database, error) { d.log.Debug("Opening data source: ", src) - dsn, err := PathFromSourceLocation(src) + dsn, err := PathFromLocation(src) if err != nil { return nil, err } @@ -77,7 +80,7 @@ func (d *Driver) Open(ctx context.Context, src *source.Source) (driver.Database, // Truncate implements driver.Driver. func (d *Driver) Truncate(ctx context.Context, src *source.Source, tbl string, reset bool) (affected int64, err error) { - dsn, err := PathFromSourceLocation(src) + dsn, err := PathFromLocation(src) if err != nil { return 0, err } @@ -118,7 +121,7 @@ func (d *Driver) ValidateSource(src *source.Source) (*source.Source, error) { // Ping implements driver.Driver. func (d *Driver) Ping(ctx context.Context, src *source.Source) error { - dbase, err := d.Open(context.TODO(), src) + dbase, err := d.Open(ctx, src) if err != nil { return err } @@ -378,24 +381,24 @@ func NewScratchSource(log lg.Log, name string) (src *source.Source, clnup func() src = &source.Source{ Type: Type, Handle: source.ScratchHandle, - Location: dbDrvr + "://" + f.Name(), + Location: Prefix + f.Name(), } return src, cleanFn, nil } -// PathFromSourceLocation returns absolute file path -// from the source location, which typically has the "sqlite3:" prefix. -func PathFromSourceLocation(src *source.Source) (string, error) { +// PathFromLocation returns the absolute file path +// from the source location, which should have the "sqlite3://" prefix. +func PathFromLocation(src *source.Source) (string, error) { if src.Type != Type { return "", errz.Errorf("driver %q does not support %q", Type, src.Type) } - if !strings.HasPrefix(src.Location, dbDrvr+":") { - return "", errz.Errorf("sqlite3 source location must begin with %q but was: %s", Type, src.RedactedLocation()) + if !strings.HasPrefix(src.Location, Prefix) { + return "", errz.Errorf("sqlite3 source location must begin with %q but was: %s", Prefix, src.RedactedLocation()) } - loc := strings.TrimPrefix(src.Location, dbDrvr+":") + loc := strings.TrimPrefix(src.Location, Prefix) if len(loc) < 2 { return "", errz.Errorf("sqlite3 source location is too short: %s", src.RedactedLocation()) } diff --git a/drivers/sqlite3/sqlite3_test.go b/drivers/sqlite3/sqlite3_test.go index f27962ad..3a99d269 100644 --- a/drivers/sqlite3/sqlite3_test.go +++ b/drivers/sqlite3/sqlite3_test.go @@ -6,6 +6,8 @@ import ( _ "github.com/mattn/go-sqlite3" "github.com/stretchr/testify/require" + "github.com/neilotoole/sq/drivers/sqlite3" + "github.com/neilotoole/sq/libsq/source" "github.com/neilotoole/sq/libsq/sqlmodel" "github.com/neilotoole/sq/libsq/sqlz" "github.com/neilotoole/sq/libsq/stringz" @@ -160,3 +162,36 @@ func TestDriver_CreateTable_NotNullDefault(t *testing.T) { require.NotNil(t, sink.Recs[0][i]) } } + +func TestPathFromLocation(t *testing.T) { + testCases := []struct { + loc string + want string + wantErr bool + }{ + {loc: "sqlite3:///test.db", want: "/test.db"}, + {loc: "postgres:///test.db", wantErr: true}, + {loc: `sqlite3://C:\dir\sakila.db`, want: `C:\dir\sakila.db`}, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.loc, func(t *testing.T) { + src := &source.Source{ + Handle: "@h1", + Type: sqlite3.Type, + Location: tc.loc, + } + + got, err := sqlite3.PathFromLocation(src) + if tc.wantErr { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } +} diff --git a/libsq/driver/driver_test.go b/libsq/driver/driver_test.go index 09f5fdec..55dd950a 100644 --- a/libsq/driver/driver_test.go +++ b/libsq/driver/driver_test.go @@ -214,7 +214,8 @@ func TestSQLDriver_PrepareUpdateStmt(t *testing.T) { func TestDriver_Ping(t *testing.T) { t.Parallel() - testCases := append(sakila.All, sakila.CSVActor, sakila.CSVActorHTTP) + testCases := sakila.All + testCases = append(testCases, sakila.CSVActor, sakila.CSVActorHTTP) for _, handle := range testCases { handle := handle @@ -235,7 +236,8 @@ func TestDriver_Ping(t *testing.T) { func TestDriver_Open(t *testing.T) { t.Parallel() - testCases := append(sakila.All, sakila.CSVActor, sakila.CSVActorHTTP) + testCases := sakila.All + testCases = append(testCases, sakila.CSVActor, sakila.CSVActorHTTP) for _, handle := range testCases { handle := handle diff --git a/libsq/source/files.go b/libsq/source/files.go index a7708f7c..83a20c5a 100644 --- a/libsq/source/files.go +++ b/libsq/source/files.go @@ -455,8 +455,11 @@ func AbsLocation(loc string) string { return loc } +// isFpath returns true if loc is a file path. func isFpath(loc string) (fpath string, ok bool) { - if strings.ContainsRune(loc, ':') { + // This is not exactly an industrial-strength algorithm... + if strings.Contains(loc, ":/") { + // Excludes "http:/" etc return "", false } diff --git a/libsq/source/internal_test.go b/libsq/source/internal_test.go index 8d5d0578..e77426a3 100644 --- a/libsq/source/internal_test.go +++ b/libsq/source/internal_test.go @@ -3,6 +3,7 @@ package source import ( "context" "io/ioutil" + "runtime" "testing" "github.com/neilotoole/lg/testlg" @@ -55,15 +56,18 @@ func TestParseLoc(t *testing.T) { loc string want parsedLoc wantErr bool + windows bool }{ {loc: "/path/to/sakila.xlsx", want: parsedLoc{name: "sakila", ext: ".xlsx"}}, {loc: "relative/path/to/sakila.xlsx", want: parsedLoc{name: "sakila", ext: ".xlsx"}}, {loc: "./relative/path/to/sakila.xlsx", want: parsedLoc{name: "sakila", ext: ".xlsx"}}, {loc: "https://server:8080/path/to/sakila.xlsx", want: parsedLoc{scheme: "https", hostname: "server", port: 8080, name: "sakila", ext: ".xlsx"}}, {loc: "http://server/path/to/sakila.xlsx?param=val¶m2=val2", want: parsedLoc{scheme: "http", hostname: "server", name: "sakila", ext: ".xlsx"}}, - {loc: "sqlite3:/path/to/sakila.db", want: parsedLoc{typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".db", dsn: "/path/to/sakila.db"}}, - {loc: "sqlite3:/path/to/sakila.sqlite", want: parsedLoc{typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".sqlite", dsn: "/path/to/sakila.sqlite"}}, - {loc: "sqlite3:/path/to/sakila", want: parsedLoc{typ: typeSL3, scheme: "sqlite3", name: "sakila", dsn: "/path/to/sakila"}}, + {loc: "sqlite3:/path/to/sakila.db", wantErr: true}, // the scheme is malformed (should be "sqlite3://...") + {loc: "sqlite3:///path/to/sakila.sqlite", want: parsedLoc{typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".sqlite", dsn: "/path/to/sakila.sqlite"}}, + {loc: `sqlite3://C:\path\to\sakila.sqlite`, windows: true, want: parsedLoc{typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".sqlite", dsn: `C:\path\to\sakila.sqlite`}}, + {loc: `sqlite3://C:\path\to\sakila.sqlite?param=val`, windows: true, want: parsedLoc{typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".sqlite", dsn: `C:\path\to\sakila.sqlite?param=val`}}, + {loc: "sqlite3:///path/to/sakila", want: parsedLoc{typ: typeSL3, scheme: "sqlite3", name: "sakila", dsn: "/path/to/sakila"}}, {loc: "sqlite3://path/to/sakila.db", want: parsedLoc{typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".db", dsn: "path/to/sakila.db"}}, {loc: "sqlite3:///path/to/sakila.db", want: parsedLoc{typ: typeSL3, scheme: "sqlite3", name: "sakila", ext: ".db", dsn: "/path/to/sakila.db"}}, {loc: "sqlserver://sakila:p_ssW0rd@localhost?database=sakila", want: parsedLoc{typ: typeMS, scheme: "sqlserver", user: dbuser, pass: dbpass, hostname: "localhost", name: "sakila", dsn: "Password=p_ssW0rd;Server=localhost;User ID=sakila;database=sakila"}}, @@ -77,6 +81,10 @@ func TestParseLoc(t *testing.T) { for _, tc := range testCases { tc := tc t.Run(tc.loc, func(t *testing.T) { + if tc.windows && runtime.GOOS != "windows" { + return + } + tc.want.loc = tc.loc // set this here rather than verbosely in the setup got, gotErr := parseLoc(tc.loc) if tc.wantErr { diff --git a/libsq/source/location.go b/libsq/source/location.go index 00e5bc5f..c4063d72 100644 --- a/libsq/source/location.go +++ b/libsq/source/location.go @@ -150,8 +150,13 @@ type parsedLoc struct { func parseLoc(loc string) (*parsedLoc, error) { ploc := &parsedLoc{loc: loc} - if !strings.ContainsRune(loc, ':') { - // no scheme: it's just a file path + if !strings.Contains(loc, "://") { + if strings.Contains(loc, ":/") { + // malformed location, such as "sqlite3:/path/to/file" + return nil, errz.Errorf("parse location: invalid scheme: %q", loc) + } + + // no scheme: it's just a regular file path for a document such as an Excel file name := filepath.Base(loc) ploc.ext = filepath.Ext(name) if ploc.ext != "" { @@ -184,20 +189,22 @@ func parseLoc(loc string) (*parsedLoc, error) { return ploc, nil } - u, err := dburl.Parse(loc) - if err != nil { - return nil, errz.Err(err) - } - - ploc.scheme = u.OriginalScheme - ploc.dsn = u.DSN - ploc.user = u.User.Username() - ploc.pass, _ = u.User.Password() - // sqlite3 is a special case, handle it now - if ploc.scheme == "sqlite3" { + const sqlitePrefix = "sqlite3://" + if strings.HasPrefix(loc, sqlitePrefix) { + fpath := strings.TrimPrefix(loc, sqlitePrefix) + + ploc.scheme = "sqlite3" ploc.typ = typeSL3 - name := path.Base(u.DSN) + ploc.dsn = fpath + + // fpath could include params, e.g. "sqlite3://C:\sakila.db?param=val" + if i := strings.IndexRune(fpath, '?'); i >= 0 { + // Snip off the params + fpath = fpath[:i] + } + + name := filepath.Base(fpath) ploc.ext = filepath.Ext(name) if ploc.ext != "" { name = name[:len(name)-len(ploc.ext)] @@ -207,6 +214,15 @@ func parseLoc(loc string) (*parsedLoc, error) { return ploc, nil } + u, err := dburl.Parse(loc) + if err != nil { + return nil, errz.Err(err) + } + + ploc.scheme = u.OriginalScheme + ploc.dsn = u.DSN + ploc.user = u.User.Username() + ploc.pass, _ = u.User.Password() ploc.hostname = u.Hostname() if u.Port() != "" { ploc.port, err = strconv.Atoi(u.Port()) diff --git a/testh/testdata/sources.sq.yml b/testh/testdata/sources.sq.yml index 1bc952ba..c5f44a5c 100644 --- a/testh/testdata/sources.sq.yml +++ b/testh/testdata/sources.sq.yml @@ -29,90 +29,90 @@ sources: location: sqlserver://sakila:p_ssW0rd@${SQ_TEST_SRC__SAKILA_MS17}?database=sakila - handle: '@sakila_xlsx' type: xlsx - location: "${SQ_ROOT}/drivers/xlsx/testdata/sakila.xlsx" + location: '${SQ_ROOT}/drivers/xlsx/testdata/sakila.xlsx' options: header: - - "true" + - 'true' - handle: '@sakila_xlsx_subset' type: xlsx - location: "${SQ_ROOT}/drivers/xlsx/testdata/sakila_subset.xlsx" + location: '${SQ_ROOT}/drivers/xlsx/testdata/sakila_subset.xlsx' options: header: - - "true" + - 'true' - handle: '@sakila_xlsx_noheader' type: xlsx - location: "${SQ_ROOT}/drivers/xlsx/testdata/sakila_noheader.xlsx" + location: '${SQ_ROOT}/drivers/xlsx/testdata/sakila_noheader.xlsx' options: header: - - "false" + - 'false' - handle: '@sakila_csv_actor' type: csv - location: "${SQ_ROOT}/drivers/csv/testdata/sakila-csv/actor.csv" + location: '${SQ_ROOT}/drivers/csv/testdata/sakila-csv/actor.csv' options: header: - - "true" + - 'true' - handle: '@sakila_csv_actor_http' type: csv - location: "https://sq.io/testdata/actor.csv" + location: 'https://sq.io/testdata/actor.csv' options: header: - - "true" + - 'true' - handle: '@sakila_csv_actor_noheader' type: csv - location: "${SQ_ROOT}/drivers/csv/testdata/sakila-csv-noheader/actor.csv" + location: '${SQ_ROOT}/drivers/csv/testdata/sakila-csv-noheader/actor.csv' options: header: - - "false" + - 'false' - handle: '@sakila_tsv_actor' type: tsv - location: "${SQ_ROOT}/drivers/csv/testdata/sakila-tsv/actor.tsv" + location: '${SQ_ROOT}/drivers/csv/testdata/sakila-tsv/actor.tsv' options: header: - - "true" + - 'true' - handle: '@sakila_tsv_actor_noheader' type: tsv - location: "${SQ_ROOT}/drivers/csv/testdata/sakila-tsv-noheader/actor.tsv" + location: '${SQ_ROOT}/drivers/csv/testdata/sakila-tsv-noheader/actor.tsv' options: header: - - "false" + - 'false' - handle: '@csv_person' type: csv - location: "${SQ_ROOT}/drivers/csv/testdata/person.csv" + location: '${SQ_ROOT}/drivers/csv/testdata/person.csv' - handle: '@csv_person_big' options: header: - - "true" + - 'true' type: csv - location: "${SQ_ROOT}/drivers/csv/testdata/person_big.csv" + location: '${SQ_ROOT}/drivers/csv/testdata/person_big.csv' - handle: '@csv_person_noheader' type: csv - location: "${SQ_ROOT}/drivers/csv/testdata/person_noheader.csv" + location: '${SQ_ROOT}/drivers/csv/testdata/person_noheader.csv' - handle: '@tsv_person' type: tsv - location: "${SQ_ROOT}/sq/drivers/csv/testdata/person.tsv" + location: '${SQ_ROOT}/sq/drivers/csv/testdata/person.tsv' - handle: '@tsv_person_noheader' type: tsv - location: "${SQ_ROOT}/drivers/csv/testdata/person_noheader.tsv" + location: '${SQ_ROOT}/drivers/csv/testdata/person_noheader.tsv' - handle: '@tsv_person_noheader_cols' type: tsv - location: "${SQ_ROOT}/drivers/csv/testdata/person_noheader.tsv" + location: '${SQ_ROOT}/drivers/csv/testdata/person_noheader.tsv' options: cols: - uid,username,email - handle: '@xl_header' type: xlsx - location: "${SQ_ROOT}/drivers/xlsx/testdata/test_header.xlsx" + location: '${SQ_ROOT}/drivers/xlsx/testdata/test_header.xlsx' - handle: '@xl_noheader' type: xlsx - location: "${SQ_ROOT}/drivers/xlsx/testdata/test_noheader.xlsx" + location: '${SQ_ROOT}/drivers/xlsx/testdata/test_noheader.xlsx' - handle: '@ud_ppl' type: ppl - location: "${SQ_ROOT}/drivers/userdriver/xmlud/testdata/people.xml" + location: '${SQ_ROOT}/drivers/userdriver/xmlud/testdata/people.xml' - handle: '@ud_rss_nytimes_local' type: rss - location: "${SQ_ROOT}/drivers/userdriver/xmlud/testdata/nytimes_local.rss.xml" + location: '${SQ_ROOT}/drivers/userdriver/xmlud/testdata/nytimes_local.rss.xml' - handle: '@miscdb' type: sqlite3 - location: "sqlite3://${SQ_ROOT}/drivers/sqlite3/testdata/misc.db" + location: 'sqlite3://${SQ_ROOT}/drivers/sqlite3/testdata/misc.db' diff --git a/testh/testh.go b/testh/testh.go index 143a036d..1b9e5d93 100644 --- a/testh/testh.go +++ b/testh/testh.go @@ -150,7 +150,7 @@ func (h *Helper) Source(handle string) *source.Source { switch src.Type { case sqlite3.Type: // This could be easily generalized for CSV/XLSX etc. - fpath, err := sqlite3.PathFromSourceLocation(src) + fpath, err := sqlite3.PathFromLocation(src) require.NoError(t, err) srcFile, err := os.Open(fpath) @@ -167,7 +167,7 @@ func (h *Helper) Source(handle string) *source.Source { _, err = io.Copy(destFile, srcFile) require.NoError(t, err) - src.Location = "sqlite3:" + destFile.Name() + src.Location = sqlite3.Prefix + destFile.Name() } h.srcCache[handle] = src return src