Skip to content

Commit

Permalink
feat(geoUtils): add searchCityByName function
Browse files Browse the repository at this point in the history
  • Loading branch information
arisGio committed Sep 22, 2024
1 parent 9e7b92e commit 8efe8de
Show file tree
Hide file tree
Showing 3 changed files with 257 additions and 0 deletions.
16 changes: 16 additions & 0 deletions docs/geoUtils.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [**getAdministrativeUnitById()**](#getAdministrativeUnitById)
- [**getMunicipalities()**](#getMunicipalities)
- [**getCities()**](#getCities)
- [**searchCityByName()**](#searchCityByName)
- [**getCityById()**](#getCityById)
- [**getCityAdministrativeDivision()**](#getCityAdministrativeDivision)
- [**getGeographicRegions()**](#getGeographicRegions)
Expand Down Expand Up @@ -298,6 +299,21 @@ The functions dealing with postal codes is listed below:

---

### searchCityByName()<a id='searchCityByName'></a>

**Description**: Searches for cities by searchTerm in a specified locale.

**Parameters:**

**`options`**: An object specifying the options for retrieval.

- **`searchTerm`**: The searchTerm with which we search through cities data.
- **`locale`** (optional, default: "el"): The locale for the city data ("el" for Greek, "en" for English).

**Return Type**: Array of `City` objects or null if nothing matches.

---

### getCityById()<a id='getCityById'></a>

**Description**: Retrieves city by its ID.
Expand Down
211 changes: 211 additions & 0 deletions src/__tests__/geoUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
getTaxOfficesByPostalCode,
getTaxOfficesByRegionId,
getTaxOfficesByUnitId,
searchCityByName,
searchTaxOffice,
} from "../geoUtils";

Expand Down Expand Up @@ -503,6 +504,216 @@ describe("getCities", () => {
});
});

describe("searchCityByName", () => {
it("should return 1 city that matches the search term 'Αθήνα' in Greek locale", () => {
// Call the method
const result = searchCityByName({ searchTerm: "Αθήνα", locale: "el" });
const expectedData = {
id: 1,
name: "Αθήνα",
coordinates: [23.726247807017884, 37.97521056577561],
relations: {
regionId: 9,
regionIso31662: "GR-I",
unitId: 42,
municipalityId: 193,
prefectureId: 1,
},
};

// Assertions
expect(result).toEqual([expectedData]);
});

it("should return 1 city that matches the search term 'athens' in English locale", () => {
// Call the method
const result = searchCityByName({ searchTerm: "athens", locale: "en" });
const expectedData = [
{
id: 1,
name: "Athens",
coordinates: [23.726247807017884, 37.97521056577561],
relations: {
regionId: 9,
regionIso31662: "GR-I",
unitId: 42,
municipalityId: 193,
prefectureId: 1,
},
},
];

// Assertions
expect(result).toEqual(expectedData);
});

it("should return null when no cities match the search term 'Spartacus'", () => {
// Call the method with a non-matching search term
const result = searchCityByName({ searchTerm: "Spartacus", locale: "en" });

// Assertions
expect(result).toBeNull();
});

it("should return all 10 matching cities when there are multiple matches for search term 'os'", () => {
// Call the method
const result = searchCityByName({ searchTerm: "os", locale: "en" });
const expectedData = [
{
coordinates: [21.442708340507092, 37.672543519754875],
id: 9,
name: "Pyrgos",
relations: {
municipalityId: 143,
prefectureId: 50,
regionId: 7,
regionIso31662: "GR-G",
unitId: 34,
},
},
{
coordinates: [22.929678443624432, 37.93909792434953],
id: 10,
name: "Korinthos",
relations: {
municipalityId: 248,
prefectureId: 39,
regionId: 10,
regionIso31662: "GR-J",
unitId: 50,
},
},
{
coordinates: [20.89750593167611, 37.78816913748807],
id: 13,
name: "Zakynthos",
relations: {
municipalityId: 117,
prefectureId: 33,
regionId: 6,
regionIso31662: "GR-F",
unitId: 27,
},
},
{
coordinates: [20.4858289731687, 38.17813591215673],
id: 15,
name: "Argostoli",
relations: {
municipalityId: 122,
prefectureId: 31,
regionId: 6,
regionIso31662: "GR-F",
unitId: 29,
},
},
{
coordinates: [22.934181911197264, 39.36398741290451],
id: 21,
name: "Bolos",
relations: {
municipalityId: 107,
prefectureId: 46,
regionId: 5,
regionIso31662: "GR-E",
unitId: 24,
},
},
{
coordinates: [23.440219134217067, 40.37701865884807],
id: 35,
name: "Polygyros",
relations: {
municipalityId: 58,
prefectureId: 10,
regionId: 2,
regionIso31662: "GR-B",
unitId: 13,
},
},
{
coordinates: [28.227254271691837, 36.44321498471273],
id: 39,
name: "Rodos",
relations: {
municipalityId: 306,
prefectureId: 43,
regionId: 12,
regionIso31662: "GR-L",
unitId: 70,
},
},
{
coordinates: [26.97515562881134, 37.7590107428132],
id: 42,
name: "Samos",
relations: {
municipalityId: 270,
prefectureId: 36,
regionId: 11,
regionIso31662: "GR-K",
unitId: 56,
},
},
{
coordinates: [26.137369911811266, 38.36388010460335],
id: 43,
name: "Xios",
relations: {
municipalityId: 274,
prefectureId: 34,
regionId: 11,
regionIso31662: "GR-K",
unitId: 57,
},
},
{
coordinates: [25.716137398247188, 35.18997128171788],
id: 45,
name: "Agios Nikolaos",
relations: {
municipalityId: 319,
prefectureId: 19,
regionId: 13,
regionIso31662: "GR-M",
unitId: 72,
},
},
];

// Assertions
expect(result).toEqual(expectedData);
});

it("should return all 3 matching cities when there are multiple matches for search term 'πολη'", () => {
// Call the method
const result = searchCityByName({ searchTerm: "πολη", locale: "el" });
const expectedData = [
{
coordinates: [22.373097659208483, 37.50979512133838],
id: 7,
name: "Τρίπολη",
relations: { municipalityId: 244, prefectureId: 37, regionId: 10, regionIso31662: "GR-J", unitId: 49 },
},
{
coordinates: [25.87239676796922, 40.84840593655441],
id: 36,
name: "Αλεξανδρούπολη",
relations: { municipalityId: 6, prefectureId: 22, regionId: 1, regionIso31662: "GR-A", unitId: 2 },
},
{
coordinates: [24.940125388382246, 37.442430072377526],
id: 40,
name: "Ερμούπολη",
relations: { municipalityId: 290, prefectureId: 42, regionId: 12, regionIso31662: "GR-L", unitId: 64 },
},
];

// Assertions
expect(result).toEqual(expectedData);
});
});

describe("getCityById", () => {
it("correctly returns city by id (in greek language)", () => {
const expectedData = cities.el[23];
Expand Down
30 changes: 30 additions & 0 deletions src/geoUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,36 @@ export function getCities({ locale = "el" }: CitiesOptions = {}): City[] {
return cities[locale];
}

type CityBySearchTermOptions = { searchTerm: string } & CitiesOptions;

/**
* Searches for cities by name in a specified locale.
*
* This function filters cities based on the provided search term. For the Greek locale (`"el"`),
* it uses a specialized string comparison function to handle Greek-specific comparisons.
* For other locales, it performs a case-insensitive comparison.
*
* @param {CityBySearchTermOptions} options - The options for the search.
* @param {string} options.searchTerm - The term to search for in the city names.
* @param {string} [options.locale="el"] - The locale to search in (default is `"el"` for Greek).
*
* @returns {City[]|null} A list of cities that match the search term, or `null` if no matches are found.
*/
export function searchCityByName({ searchTerm, locale = "el" }: CityBySearchTermOptions): City[] | null {
const cities = getCities({ locale });
let citiesByName: City[];

if (locale === "el") {
citiesByName = cities.filter((city) =>
convertsGreekTextToComparableUpperCase(city.name).includes(convertsGreekTextToComparableUpperCase(searchTerm)),
);
} else {
citiesByName = cities.filter((city) => city.name.toUpperCase().includes(searchTerm.toUpperCase()));
}

return citiesByName.length === 0 ? null : citiesByName;
}

type CityByIdOptions = { id: number } & CitiesOptions;

/**
Expand Down

0 comments on commit 8efe8de

Please sign in to comment.