Skip to content

Commit

Permalink
Merge pull request #37 from sooluh/maximizing-search-algorithm
Browse files Browse the repository at this point in the history
feat: maximizing search algorithm
  • Loading branch information
sooluh authored May 1, 2024
2 parents 99f6733 + 7b7b208 commit 8f51e88
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 42 deletions.
1 change: 0 additions & 1 deletion .prettierignore

This file was deleted.

32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,32 +87,32 @@ curl -XGET '<a href="https://kodepos.vercel.app/?q=danasari">http://localhost:30
"code": "OK",
"data": [
{
"province": "Jawa Tengah",
"regency": "Purbalingga",
"district": "Karangjambu",
"code": 46386,
"village": "Danasari",
"code": "53357"
"district": "Cisaga",
"regency": "Ciamis",
"province": "Jawa Barat"
},
{
"province": "Jawa Tengah",
"regency": "Tegal",
"district": "Bojong",
"code": 53357,
"village": "Danasari",
"code": "52465"
"district": "Karangjambu",
"regency": "Purbalingga",
"province": "Jawa Tengah"
},
{
"province": "Jawa Tengah",
"regency": "Pemalang",
"district": "Pemalang",
"code": 52314,
"village": "Danasari",
"code": "52314"
"district": "Pemalang",
"regency": "Pemalang",
"province": "Jawa Tengah"
},
{
"province": "Jawa Barat",
"regency": "Ciamis",
"district": "Cisaga",
"code": 52465,
"village": "Danasari",
"code": "46386"
"district": "Bojong",
"regency": "Tegal",
"province": "Jawa Tengah"
}
]
}
Expand Down
20 changes: 16 additions & 4 deletions app/controllers/search.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import { KeywordOptions } from '../../types'
import { createSpecResponse } from '../helpers/spec'
import { createSpecResponse, sendBadRequest } from '../helpers/spec'
import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'

export const search = (app: FastifyInstance) => {
return async (request: FastifyRequest<{ Querystring: KeywordOptions }>, reply: FastifyReply) => {
const { q } = request.query
// TODO: search by province, regency, or district
const data = app.fuse.search(q).sort((a, b) => (a.score || 0) - (b.score || 0))

reply.header('Cache-Control', 's-maxage=86400, stale-while-revalidate=604800')
if (!q) {
return sendBadRequest(reply)
}

const keywords = q
// remove duplicate spaces
.replace(/\s+/g, ' ')
.split(' ')
// add extended search per word
// https://www.fusejs.io/examples.html#extended-search
.map((i) => `'${i}`)
.join(' ')

const result = data.map(({ item }) => item)
const data = app.fuse.search(keywords)
const result = data.map(({ item: { fulltext, ...rest } }) => rest)
const response = createSpecResponse(result)

reply.header('Cache-Control', 's-maxage=86400, stale-while-revalidate=604800')
return reply.send(response)
}
}
8 changes: 8 additions & 0 deletions app/helpers/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@ export const sendNotFound = (reply: FastifyReply) => {
message: 'This endpoint cannot be found.',
})
}

export const sendBadRequest = (reply: FastifyReply) => {
return reply.status(400).send({
statusCode: 400,
code: 'BAD_REQUEST',
message: "The 'q' parameter must be filled.",
})
}
2 changes: 1 addition & 1 deletion start/app.ts → bin/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const app = async () => {
await app.register(import('@fastify/cors'))
await app.register(import('@fastify/compress'))
await app.register(import('@fastify/etag'))
await app.register(import('./core'))
await app.register(import('../start/core'))

if (process.env.ENABLE_RATE_LIMIT) {
await app.register(import('@fastify/rate-limit'), { max: 2, timeWindow: '1 second' })
Expand Down
11 changes: 0 additions & 11 deletions nodemon.json

This file was deleted.

24 changes: 21 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
"name": "@sooluh/kodepos",
"version": "4.0.0",
"description": "Indonesian postal code search API by place name, village or city",
"main": "dist/app.js",
"main": "dist/bin/app.js",
"scripts": {
"build": "npx tsc -p tsconfig.json",
"postbuild": "copyfiles data/* dist/",
"start": "node ./dist/app.js",
"start": "node ./dist/bin/app.js",
"dev": "nodemon",
"postinstall": "npm run build",
"format": "prettier --write .",
"format": "prettier . \"!data/kodepos.json\" --write",
"commit": "git-cz"
},
"engines": {
Expand Down Expand Up @@ -46,6 +46,24 @@
"prepare-commit-msg": "exec < /dev/tty && npx cz --hook || true"
}
},
"nodemonConfig": {
"restartable": "rs",
"ignore": [
".git",
"node_modules/**/node_modules"
],
"verbose": true,
"watch": [
"app",
"bin",
"start"
],
"env": {
"NODE_ENV": "development"
},
"ext": "ts",
"exec": "ts-node ./bin/app.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sooluh/kodepos.git"
Expand Down
23 changes: 21 additions & 2 deletions start/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,33 @@ import * as fs from 'node:fs/promises'
import type { DataResult } from '../types'
import type { FastifyInstance, FastifyPluginOptions } from 'fastify'

const createFullText = (data: DataResult) => {
const keys = Object.keys(data)
const combinations: string[] = []

keys.forEach((key1, index1) => {
keys.forEach((key2, index2) => {
if (index1 !== index2) {
combinations.push(`${data[key1]} ${data[key2]}`)
}
})
})

return combinations.join(' ')
}

const load = async (app: FastifyInstance, _: FastifyPluginOptions) => {
const text = await fs.readFile(path.resolve('data/kodepos.json'), { encoding: 'utf-8' })
const data: DataResult[] = JSON.parse(text)
const json: DataResult[] = JSON.parse(text)
const data = json.map((item) => ({ ...item, fulltext: createFullText(item) }))

const fuse = new Fuse(data, {
keys: ['province', 'regency', 'district', 'village', 'code'],
keys: ['fulltext'],
includeScore: true,
threshold: 0.1,
shouldSort: true,
ignoreLocation: true,
useExtendedSearch: true,
})

app.decorate('fuse', fuse)
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
"declaration": true,
"typeRoots": ["node_modules/@types", "types"]
},
"include": ["start/*.ts", "start/*.d.ts", "app/**/*.ts", "app/**/*.d.ts", "types/index.ts"],
"include": ["app/**/*.ts", "bin/app.ts", "start/*.ts", "types/index.ts"],
"exclude": ["node_modules"]
}
3 changes: 2 additions & 1 deletion types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export type DataResult = {
regency?: string
district?: string
village?: string
code?: string
code?: number
fulltext?: string
}
4 changes: 2 additions & 2 deletions vercel.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
"routes": [
{
"src": "/(.*)",
"dest": "start/app.ts"
"dest": "bin/app.ts"
}
],
"builds": [
{
"src": "start/app.ts",
"src": "bin/app.ts",
"use": "@vercel/node"
}
],
Expand Down

0 comments on commit 8f51e88

Please sign in to comment.