From 675af77965e3048a7ad29feafc7f6311aed42831 Mon Sep 17 00:00:00 2001 From: Markus Pesch Date: Fri, 6 Nov 2020 23:09:26 +0100 Subject: [PATCH] feat: import from sqlite or postgresql --- cli/imp/imp.go | 81 +++++++++++++++++++++++++++++++ cli/root.go | 2 + pkg/repository/repository.go | 92 ++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 cli/imp/imp.go diff --git a/cli/imp/imp.go b/cli/imp/imp.go new file mode 100644 index 0000000..f207816 --- /dev/null +++ b/cli/imp/imp.go @@ -0,0 +1,81 @@ +package imp + +import ( + "fmt" + "net/url" + + "git.cryptic.systems/volker.raschek/flucky/pkg/config" + "git.cryptic.systems/volker.raschek/flucky/pkg/repository" + "git.cryptic.systems/volker.raschek/go-logger" + "github.com/spf13/cobra" +) + +var ( + importSensors bool + importHumidities bool + importPressures bool + importTemperatures bool +) + +func InitCmd(cmd *cobra.Command) error { + + importCmd := &cobra.Command{ + Use: "import", + Short: "Import data from passed URL", + RunE: importSources, + } + importCmd.Flags().BoolVar(&importSensors, "sensors", true, "Import sensors") + importCmd.Flags().BoolVar(&importHumidities, "humidities", true, "Import humidities") + importCmd.Flags().BoolVar(&importPressures, "pressures", true, "Import pressures") + importCmd.Flags().BoolVar(&importTemperatures, "temperatures", true, "Import temperatures") + + cmd.AddCommand(importCmd) + + return nil +} + +func importSources(cmd *cobra.Command, args []string) error { + configFile, err := cmd.Flags().GetString("config") + if err != nil { + return fmt.Errorf("No config file defined") + } + + cnf, err := config.Read(configFile) + if err != nil { + return err + } + + destURL, err := url.Parse(cnf.DSN) + if err != nil { + return err + } + + logLevelString, err := cmd.Flags().GetString("loglevel") + if err != nil { + return err + } + + logLevel, err := logger.ParseLogLevel(logLevelString) + if err != nil { + return err + } + + flogger := logger.NewLogger(logLevel) + + sourceURL, err := url.Parse(args[0]) + if err != nil { + return fmt.Errorf("Failed to parse source url: %w", err) + } + + err = repository.Import(sourceURL, destURL, flogger, repository.OptImport{ + Sensors: importSensors, + Humidities: importHumidities, + Pressures: importPressures, + Temperatures: importTemperatures, + }) + if err != nil { + return fmt.Errorf("Failed to import: %w", err) + } + + return nil +} diff --git a/cli/root.go b/cli/root.go index c1e6dd0..b60ede6 100644 --- a/cli/root.go +++ b/cli/root.go @@ -9,6 +9,7 @@ import ( "time" "git.cryptic.systems/volker.raschek/flucky/cli/daemon" + imp "git.cryptic.systems/volker.raschek/flucky/cli/imp" "git.cryptic.systems/volker.raschek/flucky/cli/sensor" "git.cryptic.systems/volker.raschek/flucky/cli/temperature" "git.cryptic.systems/volker.raschek/flucky/pkg/config" @@ -38,6 +39,7 @@ func Execute(version *semver.Version) error { subCommands := []func(cmd *cobra.Command) error{ daemon.InitCmd, + imp.InitCmd, sensor.InitCmd, temperature.InitCmd, } diff --git a/pkg/repository/repository.go b/pkg/repository/repository.go index a1ac95e..64cbc0c 100644 --- a/pkg/repository/repository.go +++ b/pkg/repository/repository.go @@ -2,6 +2,7 @@ package repository import ( "context" + "fmt" "net/url" "strings" @@ -214,3 +215,94 @@ func New(dsnURL *url.URL, flogger logger.Logger) (*Repository, error) { database: database, }, nil } + +type OptImport struct { + Sensors bool + Humidities bool + Pressures bool + Temperatures bool +} + +func Import(sourceDSNURL *url.URL, destDNSURL *url.URL, flogger logger.Logger, optImport OptImport) error { + + importMap := map[string]bool{ + "humidities": optImport.Humidities, + "pressures": optImport.Pressures, + "temperatures": optImport.Temperatures, + } + + // enable sensors if one measured value is enabled + if !optImport.Sensors { + for key, value := range importMap { + if value { + flogger.Info("Enable import option sensors. It's required as foreign key for %v", key) + optImport.Sensors = true + } + } + } + + sourceRepo, err := New(sourceDSNURL, flogger) + if err != nil { + return fmt.Errorf("Failed to open the source repo: %w", err) + } + defer sourceRepo.Close() + + destRepo, err := New(destDNSURL, flogger) + if err != nil { + return fmt.Errorf("Failed to open the destination repo: %w", err) + } + defer destRepo.Close() + + ctx := context.Background() + devices, err := sourceRepo.database.SelectDevices(ctx) + if err != nil { + return fmt.Errorf("Failed to fetch devices from source repo: %w", err) + } + + flogger.Debug("Found %v devices", len(devices)) + + for i := range devices { + err := destRepo.AddDevices(devices[i]) + if err != nil { + return fmt.Errorf("Failed to add device %v into dest repo: %w", devices[i].Name, err) + } + } + + if optImport.Sensors { + sensors, err := sourceRepo.database.SelectSensors(ctx) + if err != nil { + return fmt.Errorf("Failed to fetch sensors from source repo: %w", err) + } + + flogger.Debug("Found %v sensors", len(sensors)) + + for i := range sensors { + err := destRepo.AddSensors(sensors[i]) + if err != nil { + return fmt.Errorf("Failed to add sensor %v into dest repo: %w", sensors[i].Name, err) + } + } + } + + for key, f := range map[string]func(context.Context) ([]*types.MeasuredValue, error){ + "humidities": sourceRepo.database.SelectHumidities, + "pressures": sourceRepo.database.SelectPressures, + "temperatures": sourceRepo.database.SelectTemperatures, + } { + if importMap[key] { + measuredValues, err := f(ctx) + if err != nil { + return fmt.Errorf("Failed to select %v from source repo: %w", key, err) + } + + flogger.Debug("Found %v %v values", len(measuredValues), key) + + err = destRepo.AddMeasuredValues(measuredValues...) + if err != nil { + return fmt.Errorf("Failed to add %v into dest repo: %w", key, err) + } + } + } + + return nil +}