Skip to content

Commit

Permalink
update: changed implementation of zipcode related methods
Browse files Browse the repository at this point in the history
  • Loading branch information
rzp-Piyush committed Nov 15, 2024
1 parent 5890f35 commit 1b9259d
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 84 deletions.
31 changes: 11 additions & 20 deletions packages/i18nify-go/country.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@ type Country struct {
}

// GetCountryMetadata retrieves metadata information for the country.
func (c Country) GetCountryMetadata() metadata.MetadataInformation {
func (c *Country) GetCountryMetadata() metadata.MetadataInformation {
return metadata.GetMetadataInformation(c.Code)
}

// GetCountryPhoneNumber retrieves telephone number information for the country.
func (c Country) GetCountryPhoneNumber() phonenumber.CountryTeleInformation {
func (c *Country) GetCountryPhoneNumber() phonenumber.CountryTeleInformation {
return phonenumber.GetCountryTeleInformation(c.Code)
}

// GetCountrySubDivisions retrieves subdivision information for the country.
func (c Country) GetCountrySubDivisions() subdivisions.CountrySubdivisions {
func (c *Country) GetCountrySubDivisions() subdivisions.CountrySubdivisions {
return subdivisions.GetCountrySubdivisions(c.Code)
}

// GetCountryCurrency retrieves currency information for the country.
func (c Country) GetCountryCurrency() []currency.CurrencyInformation {
func (c *Country) GetCountryCurrency() []currency.CurrencyInformation {
// Retrieve metadata information for the country.
countryMetadata := c.GetCountryMetadata()

Expand All @@ -43,34 +43,25 @@ func (c Country) GetCountryCurrency() []currency.CurrencyInformation {
}

// GetStatesByZipCode retrieves the states with zipcode for the country.
func (c Country) GetStatesByZipCode(zipcode string) []subdivisions.State {
subdivision := subdivisions.GetCountrySubdivisions(c.Code)
func (c *Country) GetStatesByZipCode(zipcode string) []subdivisions.State {
subdivision := c.GetCountrySubDivisions()
return subdivision.GetStatesByZipCode(zipcode)
}

// GetCitiesByZipCode retrieves the cities with zipcode for the country.
func (c Country) GetCitiesByZipCode(zipcode string) []subdivisions.City {
// Get the subdivision
subdivision := subdivisions.GetCountrySubdivisions(c.Code)
// Get list of all the states which have zipCode included.
states := subdivision.GetStatesByZipCode(zipcode)
var cities []subdivisions.City
// Get all cities with the zipCode from all the states.
for _, state := range states {
// Retrieve Cities with the zipCode from the state.
cities = append(cities, state.GetCitiesByZipCode(zipcode)...)
}
return cities
func (c *Country) GetCitiesByZipCode(zipcode string) []subdivisions.City {
subdivision := c.GetCountrySubDivisions()
return subdivision.GetCitiesWithZipCode(zipcode)
}

// IsValidZipCode returns whether a pinCode is valid for the country or not.
func (c Country) IsValidZipCode(zipcode string) bool {
func (c *Country) IsValidZipCode(zipcode string) bool {
return len(c.GetStatesByZipCode(zipcode)) > 0
}

// NewCountry creates a new Country instance with the given country code.
func NewCountry(code string) ICountry {
return Country{
return &Country{
Code: code,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import (
//go:embed data
var subDivJsonDir embed.FS

// Cache to avoid duplicate reads for same countryCode
var countrySubDivisionStore = make(map[string]CountrySubdivisions)

// DataFile is the directory where JSON files containing country subdivision data are stored. "

// UnmarshalCountrySubdivisions parses JSON data into a CountrySubdivisions struct.
Expand All @@ -33,8 +36,14 @@ func (r *CountrySubdivisions) Marshal() ([]byte, error) {

// CountrySubdivisions contains information about country subdivisions.
type CountrySubdivisions struct {
CountryName string `json:"country_name"` // CountryName represents the name of the country.
States map[string]State `json:"states"` // States contains information about states or provinces within the country.
CountryName string `json:"country_name"` // CountryName represents the name of the country.
States map[string]State `json:"states"` // States contains information about states or provinces within the country.
ZipCodes CountryZipCodeMap `json:"-"` // CountryZipCodeMap contains information for reverse lookup on zipcodes within a country
}
type CountryZipCodeMap struct {
zipcodeToStates map[string][]State
zipcodeToCities map[string][]City
IsInitialized bool
}

// GetCountryName returns the name of the country.
Expand All @@ -49,31 +58,24 @@ func (r *CountrySubdivisions) GetStates() map[string]State {

// GetStatesByZipCode returns the list of states that have at least one city with the specified zip code.
func (r *CountrySubdivisions) GetStatesByZipCode(code string) []State {
var states []State
for _, state := range r.States {
for _, city := range state.Cities {
for _, zipcode := range city.Zipcodes {
if zipcode == code {
states = append(states, state)
break
}
}
}
}
return states
return r.ZipCodes.zipcodeToStates[code]
}

// GetCitiesWithZipCode returns the list of cities with the specified zip code.
func (r *CountrySubdivisions) GetCitiesWithZipCode(code string) []City {
var cities []City
for _, state := range r.States {
cities = append(cities, state.GetCitiesByZipCode(code)...)
}
return cities
return r.ZipCodes.zipcodeToCities[code]
}

// IsValidZipCode returns if the input zipcode is valid or not
func (r *CountrySubdivisions) IsValidZipCode(code string) bool {
return len(r.ZipCodes.zipcodeToStates[code]) > 0
}

// GetCountrySubdivisions retrieves subdivision information for a specific country code.
func GetCountrySubdivisions(code string) CountrySubdivisions {
if _, present := countrySubDivisionStore[code]; present {
return countrySubDivisionStore[code]
}
// Read JSON data file containing country subdivision information.
completePath := filepath.Join("data/", code+".json")
subDivJsonData, err := subDivJsonDir.ReadFile(completePath)
Expand All @@ -83,9 +85,37 @@ func GetCountrySubdivisions(code string) CountrySubdivisions {
}
// Unmarshal JSON data into CountrySubdivisions struct.
allSubDivData, _ := UnmarshalCountrySubdivisions(subDivJsonData)
// Initialise zipcode map to get faster retrieval for Cities and States
initializeZipCodeMap(&allSubDivData)
// Store calculated CountrySubDivisions into the cache
countrySubDivisionStore[code] = allSubDivData
return allSubDivData
}

// initializeZipCodeMap builds the zip code maps for the given CountrySubdivisions.
func initializeZipCodeMap(subdivisions *CountrySubdivisions) {
// Ensure zip code maps are initialized only once.
if subdivisions.ZipCodes.IsInitialized {
return
}
var zipcodeToStates = make(map[string][]State)
var zipcodeToCities = make(map[string][]City)

// Iterate through all states and cities to populate the zip code maps.

for _, state := range subdivisions.States {
for _, city := range state.Cities {
for _, zipcode := range city.Zipcodes {
zipcodeToStates[zipcode] = append(zipcodeToStates[zipcode], state)
zipcodeToCities[zipcode] = append(zipcodeToCities[zipcode], city)
}
}
}
subdivisions.ZipCodes.zipcodeToStates = zipcodeToStates
subdivisions.ZipCodes.zipcodeToCities = zipcodeToCities
subdivisions.ZipCodes.IsInitialized = true
}

// NewCountrySubdivisions creates a new CountrySubdivisions instance.
func NewCountrySubdivisions(countryName string, states map[string]State) *CountrySubdivisions {
return &CountrySubdivisions{
Expand All @@ -105,25 +135,6 @@ func (r *State) GetCities() []City {
return r.Cities
}

// IsValidZipCode return whether input zipcode is valid or not.
func (r *State) IsValidZipCode(zipcode string) bool {
return len(r.GetCitiesByZipCode(zipcode)) > 0
}

// GetCitiesByZipCode returns the City based on the input code.
func (r *State) GetCitiesByZipCode(code string) []City {
var cities []City
for _, city := range r.Cities {
for _, zipcode := range city.Zipcodes {
if zipcode == code {
cities = append(cities, city)
break
}
}
}
return cities
}

// GetName returns the name of the state.
func (r *State) GetName() string {
return r.Name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,33 +139,26 @@ func TestGetCitiesWithZipCode(t *testing.T) {
}

func TestIsValidZipCode(t *testing.T) {
state := State{
Name: "Karnataka",
Cities: []City{
{Name: "Bengaluru", Timezone: "Asia/Kolkata", Zipcodes: []string{"560018", "560116"}},
{Name: "Mysore", Timezone: "Asia/Kolkata", Zipcodes: []string{"570001"}},
},
}

assert.True(t, state.IsValidZipCode("560116"))
assert.False(t, state.IsValidZipCode("999999"))
}

func TestGetCitiesByZipCode(t *testing.T) {
state := State{
Name: "Karnataka",
Cities: []City{
{Name: "Bengaluru", Timezone: "Asia/Kolkata", Zipcodes: []string{"560018", "560116"}},
{Name: "Mysore", Timezone: "Asia/Kolkata", Zipcodes: []string{"570001"}},
data := CountrySubdivisions{
CountryName: "India",
States: map[string]State{
"KA": {
Name: "Karnataka",
Cities: []City{
{Name: "Bengaluru", Timezone: "Asia/Kolkata", Zipcodes: []string{"560018", "560116"}},
{Name: "Mysore", Timezone: "Asia/Kolkata", Zipcodes: []string{"570001"}},
},
},
"MH": {
Name: "Maharashtra",
Cities: []City{
{Name: "Mumbai", Timezone: "Asia/Kolkata", Zipcodes: []string{"400001"}},
{Name: "Pune", Timezone: "Asia/Kolkata", Zipcodes: []string{"560116"}},
},
},
},
}

cities := state.GetCitiesByZipCode("560116")

assert.Equal(t, 1, len(cities))
assert.Equal(t, "Bengaluru", cities[0].GetName())

// Test with a zip code that does not exist
cities = state.GetCitiesByZipCode("999999")
assert.Equal(t, 0, len(cities))
assert.True(t, data.IsValidZipCode("400001"))
assert.False(t, data.IsValidZipCode("199901"))
}

0 comments on commit 1b9259d

Please sign in to comment.