├── .gitignore ├── Readme.md ├── example └── main.go ├── go.mod ├── go.sum ├── go_location.go ├── go_location_test.go ├── location.sqlite └── models.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | test/ 3 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Go Location ▲ 2 | 3 | ![banner](https://res.cloudinary.com/ichtrojan/image/upload/v1573518254/Screenshot_2019-11-12_at_01.18.23_ioaynx.png) 4 | 5 | ## Introduction 🖖 6 | 7 | This Package offers a simple way to get Countries, Cities and States that you may need for your Application, most especially for location dropdown. 8 | 9 | ## Getting Started 💽 10 | 11 | ### Install Package 12 | 13 | Install this Package by running: 14 | 15 | ```bash 16 | go get github.com/ichtrojan/go-location 17 | ``` 18 | 19 | ### Import Package 20 | 21 | ```go 22 | import "github.com/ichtrojan/go-location" 23 | ``` 24 | 25 | ## Usage 🧨 26 | 27 | This package will return the output in `structs`, you can manipulate the output however you choose. You can check the `main.go` file located in the `example` directory, the sample code in there returns the output as `JSON` to the web. 28 | 29 | ### Demo 30 | 31 | * Clone this repo: `git clone github.com/ichtrojan/go-location` 32 | * Change directory to example folder: `cd go-location/example` 33 | * Run the application: `go run main.go` 34 | * Visit application: 35 | 36 | |Endpoint|Description| 37 | |:------------- | :----------: | 38 | |`/country`|return all countries| 39 | |`/country/{id}`|return a single country by its ID| 40 | |`/state`|return all states| 41 | |`/state/{id}`|return a single state by its ID| 42 | |`/states/{countryID}`|return all states in a country using the country ID| 43 | |`/city`|return all cities| 44 | |`/city/{id}`|return a single city by its ID| 45 | |`/cities`|return all cities in a state using the state ID| 46 | 47 | ### Package Methods 48 | 49 | #### Get all countries 50 | 51 | ````go 52 | golocation.AllCountries() 53 | ```` 54 | 55 | #### Get a Country 56 | 57 | ```go 58 | golocation.GetCountry(id) 59 | ``` 60 | 61 | > **NOTE**
62 | >`id` refers to the country ID 63 | 64 | #### Get all states 65 | 66 | ```go 67 | golocation.AllStates() 68 | ``` 69 | 70 | #### Get a state 71 | 72 | ```go 73 | golocation.GetState(id) 74 | ``` 75 | 76 | > **NOTE**
77 | >`id` refers to the state ID 78 | 79 | #### Get all states in a country 80 | 81 | ```go 82 | golocation.GetCountryStates(id) 83 | ``` 84 | 85 | > **NOTE**
86 | >`id` refers to the country ID 87 | 88 | #### Get all cities 89 | 90 | ```get 91 | golocation.GetCities() 92 | ``` 93 | 94 | #### Get a city 95 | 96 | ```go 97 | golocation.GetCity(id) 98 | ``` 99 | 100 | > **NOTE**
101 | >`id` refers to the city ID 102 | 103 | #### Get cities in a state 104 | 105 | ```go 106 | golocation.GetStateCites(id) 107 | ``` 108 | 109 | > **NOTE**
110 | >`id` refers to the state ID 111 | 112 | ## Contribution 113 | 114 | Free for all, if you find an issue with the package or if a group of people somehow created a new country please send in a PR. 115 | 116 | Danke Schön 117 | -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "log" 6 | "net/http" 7 | "strconv" 8 | 9 | "github.com/gorilla/mux" 10 | golocation "github.com/ichtrojan/go-location" 11 | ) 12 | 13 | func main() { 14 | route := mux.NewRouter() 15 | golocation, err := golocation.New() 16 | if err != nil { 17 | log.Fatal(err) 18 | } 19 | 20 | route.HandleFunc("/country", func(w http.ResponseWriter, r *http.Request) { 21 | countries, err := golocation.AllCountries() 22 | if err != nil { 23 | log.Fatal(err) 24 | } 25 | 26 | _ = json.NewEncoder(w).Encode(countries) 27 | }) 28 | 29 | route.HandleFunc("/state", func(w http.ResponseWriter, r *http.Request) { 30 | states, err := golocation.AllStates() 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | 35 | _ = json.NewEncoder(w).Encode(states) 36 | }) 37 | 38 | route.HandleFunc("/city", func(w http.ResponseWriter, r *http.Request) { 39 | cities, err := golocation.AllCities() 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | 44 | _ = json.NewEncoder(w).Encode(cities) 45 | }) 46 | 47 | route.HandleFunc("/country/{id}", func(w http.ResponseWriter, r *http.Request) { 48 | vars := mux.Vars(r) 49 | 50 | id, _ := strconv.Atoi(vars["id"]) 51 | 52 | country := golocation.GetCountry(id) 53 | 54 | _ = json.NewEncoder(w).Encode(country) 55 | }) 56 | 57 | route.HandleFunc("/city/{id}", func(w http.ResponseWriter, r *http.Request) { 58 | vars := mux.Vars(r) 59 | 60 | id, _ := strconv.Atoi(vars["id"]) 61 | 62 | city, err := golocation.GetCity(id) 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | 67 | _ = json.NewEncoder(w).Encode(city) 68 | }) 69 | 70 | route.HandleFunc("/state/{id}", func(w http.ResponseWriter, r *http.Request) { 71 | vars := mux.Vars(r) 72 | 73 | id, err := strconv.Atoi(vars["id"]) 74 | 75 | state, err := golocation.GetState(id) 76 | if err != nil { 77 | log.Fatal(err) 78 | } 79 | 80 | _ = json.NewEncoder(w).Encode(state) 81 | }) 82 | 83 | route.HandleFunc("/states/{id}", func(w http.ResponseWriter, r *http.Request) { 84 | vars := mux.Vars(r) 85 | 86 | id, _ := strconv.Atoi(vars["id"]) 87 | 88 | states, err := golocation.GetCountryStates(id) 89 | if err != nil { 90 | log.Fatal(err) 91 | } 92 | 93 | _ = json.NewEncoder(w).Encode(states) 94 | }) 95 | 96 | route.HandleFunc("/cities/{id}", func(w http.ResponseWriter, r *http.Request) { 97 | vars := mux.Vars(r) 98 | 99 | id, _ := strconv.Atoi(vars["id"]) 100 | 101 | cities, err := golocation.GetStateCites(id) 102 | if err != nil { 103 | log.Fatal(err) 104 | } 105 | 106 | _ = json.NewEncoder(w).Encode(cities) 107 | }) 108 | 109 | _ = http.ListenAndServe(":9990", route) 110 | } 111 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ichtrojan/go-location 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/gorilla/mux v1.7.3 7 | github.com/mattn/go-sqlite3 v1.11.0 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= 2 | github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 3 | github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= 4 | github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 5 | -------------------------------------------------------------------------------- /go_location.go: -------------------------------------------------------------------------------- 1 | package golocation 2 | 3 | import ( 4 | "database/sql" 5 | "errors" 6 | 7 | _ "github.com/mattn/go-sqlite3" 8 | ) 9 | 10 | var ( 11 | id int 12 | code string 13 | name string 14 | phonecode int 15 | createdAt string 16 | updatedAt string 17 | countryId int 18 | stateId int 19 | database *sql.DB 20 | ) 21 | 22 | //App - This houses the unexported database, so that it wont be tampered with outside this packaage 23 | type App struct { 24 | database *sql.DB 25 | } 26 | 27 | //New - Create a new instance of the go-location package 28 | func New() (*App, error) { 29 | database, err := sql.Open("sqlite3", "../location.sqlite") 30 | if err != nil { 31 | return nil, err 32 | } 33 | app := &App{ 34 | database: database, 35 | } 36 | 37 | return app, nil 38 | } 39 | 40 | //AllCountries - Function to return the list of available countries. 41 | func (app *App) AllCountries() ([]Country, error) { 42 | //at this point, we assume that the application has been initialized successfully. 43 | database := app.database 44 | if database == nil { 45 | return nil, errors.New("Invalid Database detected") 46 | } 47 | defer database.Close() 48 | countries, err := allCountries(database) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | return countries, nil 54 | } 55 | 56 | //AllStates - Function to return all the available states. 57 | func (app *App) AllStates() ([]State, error) { 58 | database := app.database 59 | defer database.Close() 60 | 61 | statement, err := database.Query("SELECT * FROM states") 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | var states []State 67 | 68 | for statement.Next() { 69 | err = statement.Scan(&id, &name, &countryId, &createdAt, &updatedAt) 70 | if err != nil { 71 | return nil, err 72 | } 73 | 74 | state := State{ 75 | Id: id, 76 | Name: name, 77 | CountryId: countryId, 78 | } 79 | 80 | states = append(states, state) 81 | } 82 | return states, err 83 | } 84 | 85 | //AllCities - Function to return all the available cities 86 | func (app *App) AllCities() ([]City, error) { 87 | database := app.database 88 | defer database.Close() 89 | 90 | statement, err := database.Query("SELECT * FROM cities") 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | var cities []City 96 | 97 | for statement.Next() { 98 | err = statement.Scan(&id, &name, &stateId, &createdAt, &updatedAt) 99 | if err != nil { 100 | return nil, err 101 | } 102 | 103 | city := City{ 104 | Id: id, 105 | Name: name, 106 | StateId: stateId, 107 | } 108 | 109 | cities = append(cities, city) 110 | } 111 | 112 | _ = database.Close() 113 | 114 | return cities, err 115 | } 116 | 117 | //GetCountry - function to retrieve the country details 118 | func (app *App) GetCountry(countryID int) Country { 119 | database := app.database 120 | defer database.Close() 121 | 122 | statement, err := database.Query("SELECT * FROM countries WHERE id = ?", countryID) 123 | 124 | checkErr(err) 125 | 126 | var country Country 127 | 128 | defer statement.Close() 129 | 130 | for statement.Next() { 131 | err := statement.Scan(&id, &code, &name, &phonecode, &createdAt, &updatedAt) 132 | 133 | checkErr(err) 134 | 135 | country = Country{ 136 | Id: id, 137 | Code: code, 138 | Name: name, 139 | Phonecode: phonecode, 140 | } 141 | } 142 | 143 | return country 144 | } 145 | 146 | //GetCity - function to retrieve the city information 147 | func (app *App) GetCity(cityID int) (*City, error) { 148 | database = app.database 149 | defer database.Close() 150 | 151 | statement, err := database.Query("SELECT * FROM cities WHERE id = ?", cityID) 152 | if err != nil { 153 | return nil, err 154 | } 155 | 156 | var city City 157 | 158 | defer statement.Close() 159 | 160 | for statement.Next() { 161 | if err := statement.Scan(&id, &name, &stateId, &createdAt, &updatedAt); err != nil { 162 | return nil, err 163 | } 164 | 165 | city = City{ 166 | Id: id, 167 | Name: name, 168 | StateId: stateId, 169 | } 170 | } 171 | 172 | return &city, nil 173 | } 174 | 175 | //GetState - Function to retrieve the states information 176 | func (app *App) GetState(stateID int) (*State, error) { 177 | database := app.database 178 | defer database.Close() 179 | 180 | statement, err := database.Query("SELECT * FROM states WHERE id = ?", stateID) 181 | if err != nil { 182 | return nil, err 183 | } 184 | var state State 185 | defer statement.Close() 186 | 187 | for statement.Next() { 188 | if err := statement.Scan(&id, &name, &countryId, &createdAt, &updatedAt); err != nil { 189 | return nil, err 190 | } 191 | 192 | state = State{ 193 | Id: id, 194 | Name: name, 195 | CountryId: countryId, 196 | } 197 | } 198 | 199 | return &state, nil 200 | } 201 | 202 | //GetCountryStates - Function to retrieve the states related to a country 203 | func (app *App) GetCountryStates(countryID int) ([]State, error) { 204 | database := app.database 205 | statement, err := database.Query("SELECT * FROM states WHERE country_id = ?", countryID) 206 | if err != nil { 207 | return nil, err 208 | } 209 | var states []State 210 | 211 | for statement.Next() { 212 | if err = statement.Scan(&id, &name, &countryId, &createdAt, &updatedAt); err != nil { 213 | return nil, err 214 | } 215 | 216 | state := State{ 217 | Id: id, 218 | Name: name, 219 | CountryId: countryId, 220 | } 221 | 222 | states = append(states, state) 223 | } 224 | 225 | return states, nil 226 | } 227 | 228 | //GetStateCites - function to retrieve the citites that are present within a state 229 | func (app *App) GetStateCites(stateID int) ([]City, error) { 230 | database = app.database 231 | 232 | statement, err := database.Query("SELECT * FROM cities WHERE state_id = ?", stateID) 233 | if err != nil { 234 | return nil, err 235 | } 236 | 237 | var cities []City 238 | 239 | for statement.Next() { 240 | if err = statement.Scan(&id, &name, &stateId, &createdAt, &updatedAt); err != nil { 241 | return nil, err 242 | } 243 | 244 | city := City{ 245 | Id: id, 246 | Name: name, 247 | StateId: stateId, 248 | } 249 | 250 | cities = append(cities, city) 251 | } 252 | 253 | return cities, nil 254 | } 255 | 256 | func checkErr(err error) error { 257 | return err 258 | } 259 | 260 | func allCountries(database *sql.DB) ([]Country, error) { 261 | statement, err := database.Query("SELECT * FROM countries") 262 | if err != nil { 263 | return nil, err 264 | } 265 | 266 | var countries []Country 267 | 268 | for statement.Next() { 269 | err = statement.Scan(&id, &code, &name, &phonecode, &createdAt, &updatedAt) 270 | if err != nil { 271 | return nil, err 272 | } 273 | 274 | country := Country{ 275 | Id: id, 276 | Code: code, 277 | Name: name, 278 | Phonecode: phonecode, 279 | } 280 | 281 | countries = append(countries, country) 282 | } 283 | return countries, err 284 | } 285 | -------------------------------------------------------------------------------- /go_location_test.go: -------------------------------------------------------------------------------- 1 | package golocation 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "testing" 7 | ) 8 | 9 | func TestNew(t *testing.T) { 10 | app, err := New() 11 | if err != nil { 12 | log.Fatal(err) 13 | } 14 | if app == nil { 15 | log.Fatal("Invalid App returned") 16 | } 17 | } 18 | 19 | func TestEmptyDatabaseConnection(t *testing.T) { 20 | var app App 21 | countries, err := app.AllCountries() 22 | if countries != nil { 23 | log.Fatal("Countries should be nil") 24 | } 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | } 29 | 30 | func TestAllCountries(t *testing.T) { 31 | app, err := New() 32 | if err != nil { 33 | log.Fatal(err) 34 | } 35 | 36 | countries, err := app.AllCountries() 37 | if err != nil { 38 | log.Fatal(err) 39 | } 40 | 41 | fmt.Println(countries) 42 | } 43 | -------------------------------------------------------------------------------- /location.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ichtrojan/go-location/d463ded54e83695717292604f83930002ed37a42/location.sqlite -------------------------------------------------------------------------------- /models.go: -------------------------------------------------------------------------------- 1 | package golocation 2 | 3 | //Country - struct that contains the country information 4 | type Country struct { 5 | Id int `json:"id"` 6 | Code string `json:"code"` 7 | Name string `json:"name"` 8 | Phonecode int `json:"phonecode"` 9 | } 10 | 11 | //State - struct for housing the state information 12 | type State struct { 13 | Id int `json:"id"` 14 | Name string `json:"name"` 15 | CountryId int `json:"country_id"` 16 | } 17 | 18 | //City - Struct for housing the city information 19 | type City struct { 20 | Id int `json:"id"` 21 | Name string `json:"name"` 22 | StateId int `json:"state_id"` 23 | } 24 | --------------------------------------------------------------------------------