geothai
Version:
An npm package for Node.js to access detailed geographic data on Thailand, including provinces, districts, subdistricts, and postal code.
305 lines (294 loc) • 10 kB
JavaScript
let node_fs = require("node:fs");
let node_path = require("node:path");
let node_url = require("node:url");
//#region src/utils/resolve-data-path.ts
/**
* Resolves the path to a data file, checking production path first then falling back to development path
*
* @param filename - The name of the data file (e.g., "geo.json", "metadata.json")
* @param importMetaUrl - The import.meta.url from the calling module
* @returns The resolved path to the data file
*/
function resolveDataPath(filename, importMetaUrl) {
const currentDir = (0, node_path.dirname)((0, node_url.fileURLToPath)(importMetaUrl));
const srcDir = currentDir.includes("/services") ? (0, node_path.join)(currentDir, "../..") : (0, node_path.join)(currentDir, "..");
const prodPath = (0, node_path.join)(srcDir, "dist/data", filename);
const devPath = (0, node_path.join)(srcDir, "data/data/v4", filename);
return (0, node_fs.existsSync)(prodPath) ? prodPath : devPath;
}
//#endregion
//#region src/utils/cache.ts
var Cache = class {
cacheMap = /* @__PURE__ */ new Map();
defaultTTL = 3600 * 1e3;
has(key) {
const item = this.cacheMap.get(key);
if (item) {
if (item.expiry && Date.now() > item.expiry) {
this.cacheMap.delete(key);
return false;
}
return true;
}
return false;
}
get(key) {
if (this.has(key)) return this.cacheMap.get(key)?.value;
}
set(key, value, ttl) {
const expiry = Date.now() + (ttl ?? this.defaultTTL);
this.cacheMap.set(key, {
value,
expiry
});
}
clear() {
this.cacheMap.clear();
}
};
const cache = new Cache();
//#endregion
//#region src/utils/criteria-matcher.ts
/**
* Checks if an item matches the given search criteria.
*
* @param item - The item to check against the criteria
* @param criterion - The partial object containing the criteria to match
* @returns True if the item matches all criteria, false otherwise
*/
function matchCriteria(item, criterion) {
return Object.entries(criterion).every(([key, value]) => {
return item[key] === value;
});
}
//#endregion
//#region src/utils/create-service.ts
/**
* Creates a service for managing and querying a collection of data items.
*
* @param data - The array of data items to manage
* @param idKey - The key to use as the unique identifier for each item
* @returns An object with methods to query the data collection
*/
function createService(data, idKey) {
const dataMap = new Map(data.map((item) => [item[idKey], item]));
return {
getAll: () => Array.from(dataMap.values()),
getByCode: (code) => dataMap.get(Number(code)),
getByCriterion: (criterion) => {
return Array.from(dataMap.values()).filter((item) => matchCriteria(item, criterion));
}
};
}
//#endregion
//#region src/services/district.ts
const districts = JSON.parse((0, node_fs.readFileSync)(resolveDataPath("geo.json", require("url").pathToFileURL(__filename).href), "utf-8")).flatMap((province) => province.districts);
const createDistrictService = (data) => {
return createService(data, "code");
};
const districtService = createService(districts, "code");
/**
* Retrieves all districts from the database.
*
* @returns An array of all district objects
*/
function getAllDistricts() {
const key = "districts";
const cached = cache.get(key);
if (cached) return cached;
const allDistricts = districtService.getAll();
cache.set(key, allDistricts);
return allDistricts;
}
/**
* Retrieves a district by its unique code.
*
* @param code - The unique identifier code of the district
* @returns The district object if found, undefined otherwise
*/
function getDistrictByCode(code) {
const key = `district-${code}`;
const cached = cache.get(key);
if (cached) return cached;
const district = districtService.getByCode(code);
cache.set(key, district);
return district;
}
/**
* Retrieves districts that match the specified search criteria.
*
* @param criterion - The partial district object containing search criteria
* @returns An array of districts matching the criteria
*/
function getDistrictsByCriterion(criterion) {
const key = `districts-${JSON.stringify(criterion)}`;
const cached = cache.get(key);
if (cached) return cached;
const matchedDistricts = districtService.getByCriterion(criterion);
cache.set(key, matchedDistricts);
return matchedDistricts;
}
//#endregion
//#region src/utils/record-to-array.ts
/**
* Converts a record object to an array of its values.
*
* @param record - The record object to convert
* @returns An array containing all values from the record
*/
function recordToArray(record) {
return Object.values(record);
}
//#endregion
//#region src/services/postal-code.ts
const postalCodes = recordToArray(JSON.parse((0, node_fs.readFileSync)(resolveDataPath("postal_lookup.json", require("url").pathToFileURL(__filename).href), "utf-8")));
const createPostalCodeService = (data) => {
return createService(data, "postal_code");
};
const postalCodeService = createService(postalCodes, "postal_code");
/**
* Retrieves all postal codes from the database.
*
* @returns An array of all postal code objects
*/
function getAllPostalCodes() {
const key = "postal-codes";
const cached = cache.get(key);
if (cached) return cached;
const allPostalCodes = postalCodeService.getAll();
cache.set(key, allPostalCodes);
return allPostalCodes;
}
/**
* Retrieves a postal code by its unique code.
*
* @param code - The unique identifier code of the postal code
* @returns The postal code object if found, undefined otherwise
*/
function getPostalCode(code) {
const key = `postal-codes-${code}`;
const cached = cache.get(key);
if (cached) return cached;
const postalCode = postalCodeService.getByCode(code);
cache.set(key, postalCode);
return postalCode;
}
//#endregion
//#region src/services/province.ts
const provinces = JSON.parse((0, node_fs.readFileSync)(resolveDataPath("geo.json", require("url").pathToFileURL(__filename).href), "utf-8"));
const createProvinceService = (data) => {
return createService(data, "code");
};
const provinceService = createService(provinces, "code");
/**
* Retrieves all provinces from the database.
*
* @returns An array of all province objects
*/
function getAllProvinces() {
const key = "provinces";
const cached = cache.get(key);
if (cached) return cached;
const allProvinces = provinceService.getAll();
cache.set(key, allProvinces);
return allProvinces;
}
/**
* Retrieves a province by its unique code.
*
* @param code - The unique identifier code of the province
* @returns The province object if found, undefined otherwise
*/
function getProvinceByCode(code) {
const key = `province-${code}`;
const cached = cache.get(key);
if (cached) return cached;
const province = provinceService.getByCode(code);
cache.set(key, province);
return province;
}
/**
* Retrieves provinces that match the specified search criteria.
*
* @param criterion - The partial province object containing search criteria
* @returns An array of provinces matching the criteria
*/
function getProvincesByCriterion(criterion) {
const key = `provinces-${JSON.stringify(criterion)}`;
const cached = cache.get(key);
if (cached) return cached;
const matchedProvinces = provinceService.getByCriterion(criterion);
cache.set(key, matchedProvinces);
return matchedProvinces;
}
//#endregion
//#region src/services/subdistrict.ts
const subdistricts = JSON.parse((0, node_fs.readFileSync)(resolveDataPath("geo.json", require("url").pathToFileURL(__filename).href), "utf-8")).flatMap((province) => province.districts.flatMap((district) => district.subdistricts));
const createSubdistrictService = (data) => {
return createService(data, "code");
};
const subdistrictService = createService(subdistricts, "code");
/**
* Retrieves all subdistricts from the database.
*
* @returns An array of all subdistrict objects
*/
function getAllSubdistricts() {
const key = "subdistricts";
const cached = cache.get(key);
if (cached) return cached;
const allSubdistricts = subdistrictService.getAll();
cache.set(key, allSubdistricts);
return allSubdistricts;
}
/**
* Retrieves a subdistrict by its unique code.
*
* @param code - The unique identifier code of the subdistrict
* @returns The subdistrict object if found, undefined otherwise
*/
function getSubdistrictByCode(code) {
const key = `subdistrict-${code}`;
const cached = cache.get(key);
if (cached) return cached;
const subdistrict = subdistrictService.getByCode(code);
cache.set(key, subdistrict);
return subdistrict;
}
/**
* Retrieves subdistricts that match the specified search criteria.
*
* @param criterion - The partial subdistrict object containing search criteria
* @returns An array of subdistricts matching the criteria
*/
function getSubdistrictsByCriterion(criterion) {
const key = `subdistricts-${JSON.stringify(criterion)}`;
const cached = cache.get(key);
if (cached) return cached;
const matchedSubdistricts = subdistrictService.getByCriterion(criterion);
cache.set(key, matchedSubdistricts);
return matchedSubdistricts;
}
//#endregion
//#region src/index.ts
const metaData = JSON.parse((0, node_fs.readFileSync)(resolveDataPath("metadata.json", require("url").pathToFileURL(__filename).href), "utf-8"));
const metadata = metaData;
//#endregion
exports.createDistrictService = createDistrictService;
exports.createPostalCodeService = createPostalCodeService;
exports.createProvinceService = createProvinceService;
exports.createSubdistrictService = createSubdistrictService;
exports.getAllDistricts = getAllDistricts;
exports.getAllPostalCodes = getAllPostalCodes;
exports.getAllProvinces = getAllProvinces;
exports.getAllSubdistricts = getAllSubdistricts;
exports.getDistrictByCode = getDistrictByCode;
exports.getDistrictsByCriterion = getDistrictsByCriterion;
exports.getPostalCode = getPostalCode;
exports.getProvinceByCode = getProvinceByCode;
exports.getProvincesByCriterion = getProvincesByCriterion;
exports.getSubdistrictByCode = getSubdistrictByCode;
exports.getSubdistrictsByCriterion = getSubdistrictsByCriterion;
exports.matchCriteria = matchCriteria;
exports.metadata = metadata;
exports.rawProvinces = provinces;