From 1c140389488b627832e8598c521ae675181f6dbc Mon Sep 17 00:00:00 2001 From: Anton Nikiforov Date: Wed, 12 Mar 2025 10:21:02 +0300 Subject: [PATCH] [#13] locode: Add command to list all locodes Signed-off-by: Anton Nikiforov --- locode_info.go | 7 ++++--- locode_list.go | 37 +++++++++++++++++++++++++++++++++++ main.go | 3 ++- pkg/locode/db/boltdb/calls.go | 20 +++++++++++++++++++ 4 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 locode_list.go diff --git a/locode_info.go b/locode_info.go index 6263a55..e1beac1 100644 --- a/locode_info.go +++ b/locode_info.go @@ -7,8 +7,9 @@ import ( ) const ( - locodeInfoDBFlag = "db" - locodeInfoCodeFlag = "locode" + locodeInfoDBFlag = "db" + locodeInfoDBFlagDesc = "Path to FrostFS UN/LOCODE database" + locodeInfoCodeFlag = "locode" ) var ( @@ -47,7 +48,7 @@ var ( func initUtilLocodeInfoCmd() { flags := locodeInfoCmd.Flags() - flags.StringVar(&locodeInfoDBPath, locodeInfoDBFlag, "", "Path to FrostFS UN/LOCODE database") + flags.StringVar(&locodeInfoDBPath, locodeInfoDBFlag, "", locodeInfoDBFlagDesc) _ = locodeInfoCmd.MarkFlagRequired(locodeInfoDBFlag) flags.StringVar(&locodeInfoCode, locodeInfoCodeFlag, "", "UN/LOCODE") diff --git a/locode_list.go b/locode_list.go new file mode 100644 index 0000000..e4e4ad4 --- /dev/null +++ b/locode_list.go @@ -0,0 +1,37 @@ +package main + +import ( + locodedb "git.frostfs.info/TrueCloudLab/frostfs-locode-db/pkg/locode/db" + locodebolt "git.frostfs.info/TrueCloudLab/frostfs-locode-db/pkg/locode/db/boltdb" + "github.com/spf13/cobra" +) + +var ( + locodeListCmd = &cobra.Command{ + Use: "list", + Short: "Print all locodes from FrostFS database", + Run: func(cmd *cobra.Command, _ []string) { + targetDB := locodebolt.New(locodebolt.Prm{ + Path: locodeInfoDBPath, + }, locodebolt.ReadOnly()) + + err := targetDB.Open() + ExitOnErr(cmd, "", err) + + defer targetDB.Close() + + err = targetDB.IterateOverLocodes(func(locode string, geoPoint locodedb.Point) { + cmd.Printf("%s\t %0.2f %0.2f\n", locode, geoPoint.Latitude(), geoPoint.Longitude()) + }) + ExitOnErr(cmd, "", err) + }, + } +) + +func initUtilLocodeListCmd() { + flags := locodeListCmd.Flags() + + flags.StringVar(&locodeInfoDBPath, locodeInfoDBFlag, "", locodeInfoDBFlagDesc) + _ = locodeListCmd.MarkFlagRequired(locodeInfoDBFlag) + +} diff --git a/main.go b/main.go index 670ee30..8163416 100644 --- a/main.go +++ b/main.go @@ -40,7 +40,8 @@ func main() { initUtilLocodeGenerateCmd() initUtilLocodeInfoCmd() - rootCmd.AddCommand(locodeGenerateCmd, locodeInfoCmd) + initUtilLocodeListCmd() + rootCmd.AddCommand(locodeGenerateCmd, locodeInfoCmd, locodeListCmd) err := rootCmd.Execute() if err != nil { ExitOnErr(rootCmd, "", err) diff --git a/pkg/locode/db/boltdb/calls.go b/pkg/locode/db/boltdb/calls.go index d130097..d596062 100644 --- a/pkg/locode/db/boltdb/calls.go +++ b/pkg/locode/db/boltdb/calls.go @@ -164,3 +164,23 @@ func (db *DB) Get(key locodedb.Key) (rec *locodedb.Record, err error) { return } + +// IterateOverLocodes iterates over all locodes. +// +// Returns an error if unable to unmarshal data from DB. +// +// Must not be called before successful Open call. +func (db *DB) IterateOverLocodes(f func(string, locodedb.Point)) error { + return db.bolt.View(func(tx *bbolt.Tx) error { + return tx.ForEach(func(cname []byte, bktCountry *bbolt.Bucket) error { + return bktCountry.ForEach(func(k, v []byte) error { + rec, err := recordFromValue(v) + if err != nil { + return err + } + f(fmt.Sprintf("%s %s", cname, k), *rec.GeoPoint()) + return nil + }) + }) + }) +}