sq/drivers/xlsx/xlsx.go

126 lines
3.2 KiB
Go
Raw Normal View History

2020-08-06 20:58:47 +03:00
// Package xlsx implements the sq driver for Microsoft Excel.
package xlsx
import (
"context"
"log/slog"
excelize "github.com/xuri/excelize/v2"
"github.com/neilotoole/sq/libsq/core/cleanup"
"github.com/neilotoole/sq/libsq/core/errz"
"github.com/neilotoole/sq/libsq/core/lg"
"github.com/neilotoole/sq/libsq/core/lg/lga"
"github.com/neilotoole/sq/libsq/core/lg/lgm"
2020-08-06 20:58:47 +03:00
"github.com/neilotoole/sq/libsq/driver"
"github.com/neilotoole/sq/libsq/source"
)
const (
// Type is the sq source driver type for XLSX.
Type = source.DriverType("xlsx")
// laSheet is a constant for the "sheet" log attribute.
laSheet = "sheet"
2020-08-06 20:58:47 +03:00
)
// Provider implements driver.Provider.
type Provider struct {
Log *slog.Logger
2020-08-06 20:58:47 +03:00
Files *source.Files
Scratcher driver.ScratchPoolOpener
2020-08-06 20:58:47 +03:00
}
// DriverFor implements driver.Provider.
func (p *Provider) DriverFor(typ source.DriverType) (driver.Driver, error) {
2020-08-06 20:58:47 +03:00
if typ != Type {
return nil, errz.Errorf("unsupported driver type {%s}", typ)
2020-08-06 20:58:47 +03:00
}
return &Driver{log: p.Log, scratcher: p.Scratcher, files: p.Files}, nil
}
// Driver implements driver.Driver.
type Driver struct {
log *slog.Logger
scratcher driver.ScratchPoolOpener
2020-08-06 20:58:47 +03:00
files *source.Files
}
// DriverMetadata implements driver.Driver.
func (d *Driver) DriverMetadata() driver.Metadata {
return driver.Metadata{
Type: Type,
Description: "Microsoft Excel XLSX",
Doc: "https://en.wikipedia.org/wiki/Microsoft_Excel",
}
2020-08-06 20:58:47 +03:00
}
// Open implements driver.PoolOpener.
func (d *Driver) Open(ctx context.Context, src *source.Source) (driver.Pool, error) {
lg.FromContext(ctx).Debug(lgm.OpenSrc, lga.Src, src)
scratchPool, err := d.scratcher.OpenScratch(ctx, src.Handle)
2020-08-06 20:58:47 +03:00
if err != nil {
return nil, err
}
clnup := cleanup.New()
clnup.AddE(scratchPool.Close)
p := &pool{
log: d.log,
src: src,
scratchPool: scratchPool,
files: d.files,
clnup: clnup,
2020-08-06 20:58:47 +03:00
}
return p, nil
2020-08-06 20:58:47 +03:00
}
// Truncate implements driver.Driver.
2023-04-01 11:38:32 +03:00
func (d *Driver) Truncate(_ context.Context, src *source.Source, _ string, _ bool) (affected int64, err error) {
// NOTE: We could actually implement Truncate for xlsx.
// It would just mean deleting the rows from a sheet, and then
// saving the sheet. But that's probably not a game we want to
// get into, as sq doesn't currently make edits to any non-SQL
// source types.
return 0, errz.Errorf("driver type {%s} (%s) doesn't support dropping tables", Type, src.Handle)
2020-08-06 20:58:47 +03:00
}
// ValidateSource implements driver.Driver.
func (d *Driver) ValidateSource(src *source.Source) (*source.Source, error) {
d.log.Debug("Validating source", lga.Src, src)
2020-08-06 20:58:47 +03:00
if src.Type != Type {
return nil, errz.Errorf("expected driver type {%s} but got {%s}", Type, src.Type)
2020-08-06 20:58:47 +03:00
}
return src, nil
}
// Ping implements driver.Driver.
func (d *Driver) Ping(ctx context.Context, src *source.Source) (err error) {
log := lg.FromContext(ctx)
r, err := d.files.Open(src)
2020-08-06 20:58:47 +03:00
if err != nil {
return err
}
defer lg.WarnIfCloseError(log, lgm.CloseFileReader, r)
2020-08-06 20:58:47 +03:00
f, err := excelize.OpenReader(r)
2020-08-06 20:58:47 +03:00
if err != nil {
return errz.Err(err)
}
lg.WarnIfCloseError(log, lgm.CloseFileReader, f)
2020-08-06 20:58:47 +03:00
return nil
}
func errw(err error) error {
return errz.Wrap(err, "excel")
}