geothai
Version:
An npm package for Node.js to access detailed geographic data on Thailand, including provinces, districts, subdistricts, and postal code.
1 lines • 17.1 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":[],"sources":["../src/utils/resolve-data-path.ts","../src/utils/cache.ts","../src/utils/criteria-matcher.ts","../src/utils/create-service.ts","../src/services/district.ts","../src/utils/record-to-array.ts","../src/services/postal-code.ts","../src/services/province.ts","../src/services/subdistrict.ts","../src/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Resolves the path to a data file, checking production path first then falling back to development path\n *\n * @param filename - The name of the data file (e.g., \"geo.json\", \"metadata.json\")\n * @param importMetaUrl - The import.meta.url from the calling module\n * @returns The resolved path to the data file\n */\nexport function resolveDataPath(\n filename: string,\n importMetaUrl: string,\n): string {\n const currentDir = dirname(fileURLToPath(importMetaUrl));\n\n // Find the project root by looking for the src directory\n // From src/services -> go up 2 levels\n // From src -> go up 1 level\n const srcDir = currentDir.includes(\"/services\")\n ? join(currentDir, \"../..\")\n : join(currentDir, \"..\");\n\n const prodPath = join(srcDir, \"dist/data\", filename);\n const devPath = join(srcDir, \"data/data/v4\", filename);\n\n return existsSync(prodPath) ? prodPath : devPath;\n}\n","type CacheItem<T> = {\n value: T;\n expiry?: number;\n};\n\nclass Cache {\n private readonly cacheMap: Map<string, CacheItem<unknown>> = new Map();\n private readonly defaultTTL: number = 60 * 60 * 1000; // 1 hour in milliseconds\n\n public has(key: string): boolean {\n const item = this.cacheMap.get(key);\n if (item) {\n if (item.expiry && Date.now() > item.expiry) {\n this.cacheMap.delete(key);\n return false;\n }\n return true;\n }\n return false;\n }\n\n public get<T>(key: string): T | undefined {\n if (this.has(key)) {\n return this.cacheMap.get(key)?.value as T;\n }\n return undefined;\n }\n\n public set<T>(key: string, value: T, ttl?: number): void {\n const expiry = Date.now() + (ttl ?? this.defaultTTL);\n this.cacheMap.set(key, { value, expiry });\n }\n\n public clear(): void {\n this.cacheMap.clear();\n }\n}\n\nexport const cache = new Cache();\n","/**\n * Checks if an item matches the given search criteria.\n *\n * @param item - The item to check against the criteria\n * @param criterion - The partial object containing the criteria to match\n * @returns True if the item matches all criteria, false otherwise\n */\nexport function matchCriteria<T>(item: T, criterion: Partial<T>): boolean {\n return Object.entries(criterion).every(([key, value]) => {\n return item[key as keyof T] === value;\n });\n}\n","import { matchCriteria } from \"./criteria-matcher\";\n\n/**\n * Creates a service for managing and querying a collection of data items.\n *\n * @param data - The array of data items to manage\n * @param idKey - The key to use as the unique identifier for each item\n * @returns An object with methods to query the data collection\n */\nexport function createService<T>(data: T[], idKey: keyof T) {\n const dataMap = new Map<number, T>(\n data.map((item) => [item[idKey] as number, item]),\n );\n\n return {\n getAll: (): T[] => Array.from(dataMap.values()),\n getByCode: (code: string): T | undefined => dataMap.get(Number(code)),\n getByCriterion: (criterion: Partial<T>): T[] => {\n return Array.from(dataMap.values()).filter((item) =>\n matchCriteria(item, criterion),\n );\n },\n };\n}\n","import { readFileSync } from \"node:fs\";\nimport type { District, DistrictIndex, Province } from \"../types\";\nimport { cache } from \"../utils/cache\";\nimport { createService } from \"../utils/create-service\";\nimport { resolveDataPath } from \"../utils/resolve-data-path\";\n\nconst provinces = JSON.parse(\n readFileSync(resolveDataPath(\"geo.json\", import.meta.url), \"utf-8\"),\n) as Province[];\n\n// Flatten all districts from all provinces\nconst districts: District[] = provinces.flatMap(\n (province) => province.districts,\n);\n\nexport const createDistrictService = (data: District[]) => {\n return createService<District>(data, \"code\");\n};\n\nconst districtService = createService<District>(districts, \"code\");\n\n/**\n * Retrieves all districts from the database.\n *\n * @returns An array of all district objects\n */\nexport function getAllDistricts(): District[] {\n const key = \"districts\";\n const cached = cache.get<District[]>(key);\n if (cached) {\n return cached;\n }\n const allDistricts = districtService.getAll();\n cache.set<District[]>(key, allDistricts);\n return allDistricts;\n}\n\n/**\n * Retrieves a district by its unique code.\n *\n * @param code - The unique identifier code of the district\n * @returns The district object if found, undefined otherwise\n */\nexport function getDistrictByCode(code: DistrictIndex): District | undefined {\n const key = `district-${code}`;\n const cached = cache.get<District>(key);\n if (cached) {\n return cached;\n }\n const district = districtService.getByCode(code);\n cache.set(key, district);\n return district;\n}\n\n/**\n * Retrieves districts that match the specified search criteria.\n *\n * @param criterion - The partial district object containing search criteria\n * @returns An array of districts matching the criteria\n */\nexport function getDistrictsByCriterion(\n criterion: Partial<District>,\n): District[] {\n const key = `districts-${JSON.stringify(criterion)}`;\n const cached = cache.get<District[]>(key);\n if (cached) {\n return cached;\n }\n const matchedDistricts = districtService.getByCriterion(criterion);\n cache.set(key, matchedDistricts);\n return matchedDistricts;\n}\n","/**\n * Converts a record object to an array of its values.\n *\n * @param record - The record object to convert\n * @returns An array containing all values from the record\n */\nexport function recordToArray<K extends string | number | symbol, T>(\n record: Record<K, T>,\n): T[] {\n return Object.values(record);\n}\n","import { readFileSync } from \"node:fs\";\nimport type { PostalCode, PostalCodeIndex } from \"../types\";\nimport { cache } from \"../utils/cache\";\nimport { createService } from \"../utils/create-service\";\nimport { recordToArray } from \"../utils/record-to-array\";\nimport { resolveDataPath } from \"../utils/resolve-data-path\";\n\nconst postalLookup = JSON.parse(\n readFileSync(resolveDataPath(\"postal_lookup.json\", import.meta.url), \"utf-8\"),\n) as Record<string, PostalCode>;\nconst postalCodes = recordToArray(postalLookup);\n\nexport const createPostalCodeService = (data: PostalCode[]) => {\n return createService<PostalCode>(data, \"postal_code\");\n};\n\nconst postalCodeService = createService<PostalCode>(postalCodes, \"postal_code\");\n\n/**\n * Retrieves all postal codes from the database.\n *\n * @returns An array of all postal code objects\n */\nexport function getAllPostalCodes(): PostalCode[] {\n const key = \"postal-codes\";\n const cached = cache.get<PostalCode[]>(key);\n if (cached) {\n return cached;\n }\n const allPostalCodes = postalCodeService.getAll();\n cache.set<PostalCode[]>(key, allPostalCodes);\n return allPostalCodes;\n}\n\n/**\n * Retrieves a postal code by its unique code.\n *\n * @param code - The unique identifier code of the postal code\n * @returns The postal code object if found, undefined otherwise\n */\nexport function getPostalCode(code: PostalCodeIndex): PostalCode | undefined {\n const key = `postal-codes-${code}`;\n const cached = cache.get<PostalCode>(key);\n if (cached) {\n return cached;\n }\n const postalCode = postalCodeService.getByCode(code);\n cache.set(key, postalCode);\n return postalCode;\n}\n","import { readFileSync } from \"node:fs\";\nimport type { Province, ProvinceIndex } from \"../types\";\nimport { cache } from \"../utils/cache\";\nimport { createService } from \"../utils/create-service\";\nimport { resolveDataPath } from \"../utils/resolve-data-path\";\n\nconst provinces = JSON.parse(\n readFileSync(resolveDataPath(\"geo.json\", import.meta.url), \"utf-8\"),\n) as Province[];\n\nexport const createProvinceService = (data: Province[]) => {\n return createService<Province>(data, \"code\");\n};\n\nconst provinceService = createService<Province>(provinces, \"code\");\n\n/**\n * Retrieves all provinces from the database.\n *\n * @returns An array of all province objects\n */\nexport function getAllProvinces(): Province[] {\n const key = \"provinces\";\n const cached = cache.get<Province[]>(key);\n if (cached) {\n return cached;\n }\n const allProvinces = provinceService.getAll();\n cache.set<Province[]>(key, allProvinces);\n return allProvinces;\n}\n\n/**\n * Retrieves a province by its unique code.\n *\n * @param code - The unique identifier code of the province\n * @returns The province object if found, undefined otherwise\n */\nexport function getProvinceByCode(code: ProvinceIndex): Province | undefined {\n const key = `province-${code}`;\n const cached = cache.get<Province>(key);\n if (cached) {\n return cached;\n }\n const province = provinceService.getByCode(code);\n cache.set(key, province);\n return province;\n}\n\n/**\n * Retrieves provinces that match the specified search criteria.\n *\n * @param criterion - The partial province object containing search criteria\n * @returns An array of provinces matching the criteria\n */\nexport function getProvincesByCriterion(\n criterion: Partial<Province>,\n): Province[] {\n const key = `provinces-${JSON.stringify(criterion)}`;\n const cached = cache.get<Province[]>(key);\n if (cached) {\n return cached;\n }\n const matchedProvinces = provinceService.getByCriterion(criterion);\n cache.set(key, matchedProvinces);\n return matchedProvinces;\n}\n\n// Export the raw data for other services\nexport { provinces as rawProvinces };\n","import { readFileSync } from \"node:fs\";\nimport type { Province, Subdistrict, SubdistrictIndex } from \"../types\";\nimport { cache } from \"../utils/cache\";\nimport { createService } from \"../utils/create-service\";\nimport { resolveDataPath } from \"../utils/resolve-data-path\";\n\nconst provinces = JSON.parse(\n readFileSync(resolveDataPath(\"geo.json\", import.meta.url), \"utf-8\"),\n) as Province[];\n\n// Flatten all subdistricts from all districts from all provinces\nconst subdistricts: Subdistrict[] = provinces.flatMap((province) =>\n province.districts.flatMap((district) => district.subdistricts),\n);\n\nexport const createSubdistrictService = (data: Subdistrict[]) => {\n return createService<Subdistrict>(data, \"code\");\n};\n\nconst subdistrictService = createService<Subdistrict>(subdistricts, \"code\");\n\n/**\n * Retrieves all subdistricts from the database.\n *\n * @returns An array of all subdistrict objects\n */\nexport function getAllSubdistricts(): Subdistrict[] {\n const key = \"subdistricts\";\n const cached = cache.get<Subdistrict[]>(key);\n if (cached) {\n return cached;\n }\n const allSubdistricts = subdistrictService.getAll();\n cache.set<Subdistrict[]>(key, allSubdistricts);\n return allSubdistricts;\n}\n\n/**\n * Retrieves a subdistrict by its unique code.\n *\n * @param code - The unique identifier code of the subdistrict\n * @returns The subdistrict object if found, undefined otherwise\n */\nexport function getSubdistrictByCode(\n code: SubdistrictIndex,\n): Subdistrict | undefined {\n const key = `subdistrict-${code}`;\n const cached = cache.get<Subdistrict>(key);\n if (cached) {\n return cached;\n }\n const subdistrict = subdistrictService.getByCode(code);\n cache.set(key, subdistrict);\n return subdistrict;\n}\n\n/**\n * Retrieves subdistricts that match the specified search criteria.\n *\n * @param criterion - The partial subdistrict object containing search criteria\n * @returns An array of subdistricts matching the criteria\n */\nexport function getSubdistrictsByCriterion(\n criterion: Partial<Subdistrict>,\n): Subdistrict[] {\n const key = `subdistricts-${JSON.stringify(criterion)}`;\n const cached = cache.get<Subdistrict[]>(key);\n if (cached) {\n return cached;\n }\n const matchedSubdistricts = subdistrictService.getByCriterion(criterion);\n cache.set(key, matchedSubdistricts);\n return matchedSubdistricts;\n}\n","import { readFileSync } from \"node:fs\";\nimport type { Metadata } from \"./types\";\nimport { resolveDataPath } from \"./utils/resolve-data-path\";\n\nexport * from \"./services/district\";\nexport * from \"./services/postal-code\";\nexport * from \"./services/province\";\nexport * from \"./services/subdistrict\";\nexport * from \"./types\";\nexport * from \"./utils/criteria-matcher\";\n\nconst metaData = JSON.parse(\n readFileSync(resolveDataPath(\"metadata.json\", import.meta.url), \"utf-8\"),\n) as Metadata;\n\nexport const metadata: Metadata = metaData;\n"],"mappings":"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"}