UNPKG

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
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;