Skip to content

Commit

Permalink
locodedb: drop useless types from exported package
Browse files Browse the repository at this point in the history
Drop `Key`, `CountryCode` and `LocationCode` from exported package. Refactor the
code and remove unnecessary constructs and functions.

Closes #46.

Signed-off-by: Andrey Butusov <andrey@nspcc.io>
  • Loading branch information
End-rey committed Feb 28, 2025
1 parent aa7378f commit 612e82a
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 146 deletions.
6 changes: 2 additions & 4 deletions internal/parsers/db/airports/calls.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,13 @@ const (
// and returns the name of the country by code.
//
// Returns locodedb.ErrCountryNotFound if no entry matches.
func (db *DB) CountryName(code *locodedb.CountryCode) (name string, err error) {
func (db *DB) CountryName(code string) (name string, err error) {

Check warning on line 97 in internal/parsers/db/airports/calls.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/airports/calls.go#L97

Added line #L97 was not covered by tests
if err = db.initCountries(); err != nil {
return
}

argCode := code.String()

for cName, cCode := range db.mCountries {
if cCode == argCode {
if cCode == code {

Check warning on line 103 in internal/parsers/db/airports/calls.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/airports/calls.go#L103

Added line #L103 was not covered by tests
name = cName
break
}
Expand Down
6 changes: 3 additions & 3 deletions internal/parsers/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ type NamesDB interface {
//
// Must return ErrCountryNotFound if there is no
// country with the provided code.
CountryName(*locodedb.CountryCode) (string, error)
CountryName(string) (string, error)

// SubDivName must resolve (country code, subdivision code) to
// a subdivision name.
//
// Must return ErrSubDivNotFound if either country or
// subdivision is not presented in database.
SubDivName(*locodedb.CountryCode, string) (string, error)
SubDivName(string, string) (string, error)
}

// FillDatabase generates the location database based on the UN/LOCODE table.
Expand All @@ -72,7 +72,7 @@ func FillDatabase(table SourceTable, airports AirportDB, continents ContinentsDB
return nil
}

dbKey, err := locodedb.NewKey(tableRecord.LOCODE[0], tableRecord.LOCODE[1])
dbKey, err := NewKey(tableRecord.LOCODE[0], tableRecord.LOCODE[1])

Check warning on line 75 in internal/parsers/db/db.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/db.go#L75

Added line #L75 was not covered by tests
if err != nil {
return err
}
Expand Down
64 changes: 64 additions & 0 deletions internal/parsers/db/key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package locodedb

import (
"fmt"

"github.com/nspcc-dev/locode-db/pkg/locodedb"
)

// Key represents the Key in location database. It contains the country code and the location code.
type Key struct {
cc string
lc string
}

// NewKey returns a new Key from a country code and a location code string pair (e.g. "USNYC") or an error if
// the string is invalid. The country code must be 2 letters long and the location code 3 letters long.
func NewKey(country, location string) (*Key, error) {
err := validateCode(country, locodedb.CountryCodeLen)
if err != nil {
return nil, fmt.Errorf("could not parse country: %w", err)
}

Check warning on line 21 in internal/parsers/db/key.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/key.go#L17-L21

Added lines #L17 - L21 were not covered by tests

err = validateCode(location, locodedb.LocationCodeLen)
if err != nil {
return nil, fmt.Errorf("could not parse location: %w", err)
}

Check warning on line 26 in internal/parsers/db/key.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/key.go#L23-L26

Added lines #L23 - L26 were not covered by tests

return &Key{
cc: country,
lc: location,
}, nil

Check warning on line 31 in internal/parsers/db/key.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/key.go#L28-L31

Added lines #L28 - L31 were not covered by tests
}

// CountryCode returns the location's country code in string representation.
func (k *Key) CountryCode() string {
return k.cc

Check warning on line 36 in internal/parsers/db/key.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/key.go#L35-L36

Added lines #L35 - L36 were not covered by tests
}

// LocationCode returns the location code in string representation.
func (k *Key) LocationCode() string {
return k.lc

Check warning on line 41 in internal/parsers/db/key.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/key.go#L40-L41

Added lines #L40 - L41 were not covered by tests
}

// validateCode validates if code is.
func validateCode(s string, codeLen int) error {
if l := len(s); l != codeLen {
return fmt.Errorf("incorrect location code length: expect: %d, got: %d",
codeLen,
l,
)
}

Check warning on line 51 in internal/parsers/db/key.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/key.go#L45-L51

Added lines #L45 - L51 were not covered by tests

for i := range s {
if !isUpperAlpha(s[i]) && !isDigit(s[i]) {
return locodedb.ErrInvalidString
}

Check warning on line 56 in internal/parsers/db/key.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/key.go#L53-L56

Added lines #L53 - L56 were not covered by tests
}

return nil

Check warning on line 59 in internal/parsers/db/key.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/key.go#L59

Added line #L59 was not covered by tests
}

func isUpperAlpha(sym uint8) bool {
return sym >= 'A' && sym <= 'Z'

Check warning on line 63 in internal/parsers/db/key.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/key.go#L62-L63

Added lines #L62 - L63 were not covered by tests
}
10 changes: 5 additions & 5 deletions internal/parsers/db/put.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const (

// Data is a struct that contains the Key and the Record.
type Data struct {
Key locodedb.Key
Key Key
Record locodedb.Record
}

Expand All @@ -40,7 +40,7 @@ func (db *CsvDB) Put(data []Data) error {
rec := row.Record

// Calculate a unique index for each key
keyString := key.CountryCode().String() + key.LocationCode().String()
keyString := key.CountryCode() + key.LocationCode()

Check warning on line 43 in internal/parsers/db/put.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/put.go#L43

Added line #L43 was not covered by tests

if index, exists := uniqueKeys[keyString]; exists {
// We expected duplicates from override.csv to override wrong number format in location
Expand All @@ -64,14 +64,14 @@ func (db *CsvDB) Put(data []Data) error {

newRecordsLocode = append(newRecordsLocode, newRecord)

if _, exists := uniqueKeysCountry[key.CountryCode().String()]; exists {
if _, exists := uniqueKeysCountry[key.CountryCode()]; exists {

Check warning on line 67 in internal/parsers/db/put.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/put.go#L67

Added line #L67 was not covered by tests
continue
}

uniqueKeysCountry[key.CountryCode().String()] = struct{}{}
uniqueKeysCountry[key.CountryCode()] = struct{}{}

Check warning on line 71 in internal/parsers/db/put.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/put.go#L71

Added line #L71 was not covered by tests

newRecordCountry := []string{
key.CountryCode().String(),
key.CountryCode(),

Check warning on line 74 in internal/parsers/db/put.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/db/put.go#L74

Added line #L74 was not covered by tests
rec.Country,
}

Expand Down
5 changes: 2 additions & 3 deletions internal/parsers/table/csv/calls.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"unicode/utf8"

locode "github.com/nspcc-dev/locode-db/internal/parsers/db"
"github.com/nspcc-dev/locode-db/pkg/locodedb"
"golang.org/x/text/encoding/charmap"
)

Expand Down Expand Up @@ -67,13 +66,13 @@ type subDivRecord struct {
// and returns the subdivision name of the country and the subdivision codes match.
//
// Returns locodedb.ErrSubDivNotFound if no entry matches.
func (t *Table) SubDivName(countryCode *locodedb.CountryCode, code string) (string, error) {
func (t *Table) SubDivName(countryCode string, code string) (string, error) {

Check warning on line 69 in internal/parsers/table/csv/calls.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/table/csv/calls.go#L69

Added line #L69 was not covered by tests
if err := t.initSubDiv(); err != nil {
return "", err
}

rec, ok := t.mSubDiv[subDivKey{
countryCode: countryCode.String(),
countryCode: countryCode,

Check warning on line 75 in internal/parsers/table/csv/calls.go

View check run for this annotation

Codecov / codecov/patch

internal/parsers/table/csv/calls.go#L75

Added line #L75 was not covered by tests
subDivCode: code,
}]
if !ok {
Expand Down
12 changes: 4 additions & 8 deletions pkg/locodedb/calls.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var (
locodeStrings string

// mCountries is a map of country codes to country names and locodes.
mCountries map[CountryCode]countryData
mCountries map[countryCode]countryData
)

// Get returns a record for a given locode string. The string must be 5 or 6
Expand Down Expand Up @@ -44,7 +44,7 @@ func Get(locodeStr string) (Record, error) {
}
}

cc := CountryCode{}
cc := countryCode{}
copy(cc[:], locodeStr[:2])
cd, countryFound := mCountries[cc]
if !countryFound {
Expand All @@ -53,9 +53,9 @@ func Get(locodeStr string) (Record, error) {

code := locodeStr[CountryCodeLen:]
n, _ := slices.BinarySearchFunc(cd.locodes, code, func(csv locodesCSV, s string) int {
return cmp.Compare(codeFromCSV(&csv), s)
return cmp.Compare(csv.code, s)
})
if n == len(cd.locodes) || strings.Compare(codeFromCSV(&cd.locodes[n]), code) != 0 {
if n == len(cd.locodes) || strings.Compare(cd.locodes[n].code, code) != 0 {
return Record{}, ErrNotFound
}

Expand All @@ -69,10 +69,6 @@ func Get(locodeStr string) (Record, error) {
}, nil
}

func codeFromCSV(c *locodesCSV) string {
return string(c.code[:])
}

func locFromCSV(c *locodesCSV) string {
return locodeStrings[c.offset : c.offset+uint32(c.locationLen)]
}
Expand Down
4 changes: 0 additions & 4 deletions pkg/locodedb/calls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,4 @@ func TestGet(t *testing.T) {
require.Equal(t, utf8.ValidString(rec.SubDivName), true)
})
})
t.Run("valid key", func(t *testing.T) {
_, err := locodedb.NewKey("RU", "MOW")
require.NoError(t, err)
})
}
28 changes: 16 additions & 12 deletions pkg/locodedb/country.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
package locodedb

import (
"errors"
"fmt"
)

// CountryCodeLen is the length of the country code.
const CountryCodeLen = 2

// CountryCode represents ISO 3166 alpha-2 Country Code.
type CountryCode [CountryCodeLen]uint8
// LocationCodeLen is the length of the location code.
const LocationCodeLen = 3

// CountryCodeFromString parses a string and returns the country code.
func CountryCodeFromString(s string) (*CountryCode, error) {
// ErrInvalidString is returned when the string is not a valid location code.
var ErrInvalidString = errors.New("invalid string format in UN/Locode")

// countryCode represents ISO 3166 alpha-2 Country Code.
type countryCode [CountryCodeLen]uint8

// countryCodeFromString parses a string and returns the country code.
func countryCodeFromString(s string) (*countryCode, error) {
if l := len(s); l != CountryCodeLen {
return nil, fmt.Errorf("incorrect country code length: expect: %d, got: %d",
CountryCodeLen,
Expand All @@ -25,19 +32,16 @@ func CountryCodeFromString(s string) (*CountryCode, error) {
}
}

cc := CountryCode{}
cc := countryCode{}
copy(cc[:], s)

return &cc, nil
}

// String returns a string representation of the country code.
func (c *CountryCode) String() string {
syms := c.Symbols()
return string(syms[:])
func isUpperAlpha(sym uint8) bool {
return sym >= 'A' && sym <= 'Z'
}

// Symbols returns the country code as a slice of symbols.
func (c *CountryCode) Symbols() [CountryCodeLen]uint8 {
return *c
func isDigit(sym uint8) bool {
return sym >= '0' && sym <= '9'

Check warning on line 46 in pkg/locodedb/country.go

View check run for this annotation

Codecov / codecov/patch

pkg/locodedb/country.go#L45-L46

Added lines #L45 - L46 were not covered by tests
}
56 changes: 0 additions & 56 deletions pkg/locodedb/location.go

This file was deleted.

39 changes: 0 additions & 39 deletions pkg/locodedb/record.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,5 @@
package locodedb

import (
"fmt"
)

// Key represents the key in location database. It contains the country code and the location code.
type Key struct {
cc *CountryCode
lc *LocationCode
}

// NewKey returns a new Key from a country code and a location code string pair (e.g. "USNYC") or an error if
// the string is invalid. The country code must be 2 letters long and the location code 3 letters long.
func NewKey(country, location string) (*Key, error) {
countryCode, err := CountryCodeFromString(country)
if err != nil {
return nil, fmt.Errorf("could not parse country: %w", err)
}

locationCode, err := LocationCodeFromString(location)
if err != nil {
return nil, fmt.Errorf("could not parse location: %w", err)
}

return &Key{
cc: countryCode,
lc: locationCode,
}, nil
}

// CountryCode returns the location's country code.
func (k *Key) CountryCode() *CountryCode {
return k.cc
}

// LocationCode returns the location code.
func (k *Key) LocationCode() *LocationCode {
return k.lc
}

// Record represents a record in the location database (resulting CSV files). It contains all the
// information about the location. It is used to fill the database. Country, Location are full names, codes are in Key.
type Record struct {
Expand Down
Loading

0 comments on commit 612e82a

Please sign in to comment.