rename search to all
This commit is contained in:
1 parent
d6142bca01
commit
33c6381a7c
3 files changed
+41
-16
No files matched your search
+180
@@ -0,0 +1,180 @@
|
||||
import { sql } from '@databases/pg'
|
||||
import { FastifyPluginAsync } from 'fastify'
|
||||
import S from 'jsonschema-definer'
|
||||
|
||||
import { db } from '../shared'
|
||||
import { QSplit, pgOp, qParseNum } from '../util/search'
|
||||
|
||||
export const allRouter: FastifyPluginAsync = async (f) => {
|
||||
{
|
||||
const sQuery = S.shape({
|
||||
q: S.string(),
|
||||
offset: S.integer().optional(),
|
||||
limit: S.integer().optional(),
|
||||
distinct: S.string().enum('id').optional(),
|
||||
})
|
||||
|
||||
const sResponse = S.shape({
|
||||
result: S.list(
|
||||
S.shape({
|
||||
entry: S.string(),
|
||||
type: S.string(),
|
||||
}).additionalProperties(true)
|
||||
),
|
||||
offset: S.integer(),
|
||||
limit: S.integer(),
|
||||
count: S.integer(),
|
||||
})
|
||||
|
||||
const makeEntry = new QSplit({
|
||||
default(v) {
|
||||
if (v.includes('*')) {
|
||||
return sql`"entry" && (
|
||||
SELECT array_agg("entry") FROM "frequency" WHERE "entry" LIKE ${
|
||||
'%' + v.replace('*', '%') + '%'
|
||||
}
|
||||
)`
|
||||
}
|
||||
|
||||
if (/[\p{sc=Han}\p{sc=Katakana}\p{sc=Hiragana}]/u.test(v)) {
|
||||
return sql`(${sql.join(
|
||||
[
|
||||
this.fields['entry']![':']!(v),
|
||||
this.fields['reading']![':']!(v),
|
||||
this.fields['translation']![':']!(v),
|
||||
],
|
||||
' OR '
|
||||
)})`
|
||||
}
|
||||
|
||||
if (/[^\p{L}\p{N}\p{M} :-]/u.test(v)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return sql`(${sql.join(
|
||||
[
|
||||
this.fields['reading']![':']!(v),
|
||||
this.fields['translation']![':']!(v),
|
||||
],
|
||||
' OR '
|
||||
)})`
|
||||
},
|
||||
fields: {
|
||||
entry: { ':': (v) => sql`"entry" &@ ${v}` },
|
||||
kana: { ':': (v) => sql`"reading" &@ ${v}` },
|
||||
reading: { ':': (v) => sql`"reading" &@ ${v}` },
|
||||
kunyomi: {
|
||||
':': (v) =>
|
||||
sql`"reading" ${pgOp} ${`paths @ ".kunyomi" && string @ ${JSON.stringify(
|
||||
v
|
||||
)}`}`,
|
||||
},
|
||||
onyomi: {
|
||||
':': (v) =>
|
||||
sql`"reading" ${pgOp} ${`paths @ ".onyomi" && string @ ${JSON.stringify(
|
||||
v
|
||||
)}`}`,
|
||||
},
|
||||
nanori: {
|
||||
':': (v) =>
|
||||
sql`"reading" ${pgOp} ${`paths @ ".nanori" && string @ ${JSON.stringify(
|
||||
v
|
||||
)}`}`,
|
||||
},
|
||||
english: {
|
||||
':': (v) =>
|
||||
sql`"translation" ${pgOp} ${`paths @ ".en" && string @ ${JSON.stringify(
|
||||
v
|
||||
)}`}`,
|
||||
},
|
||||
translation: { ':': (v) => sql`"translation" &@ ${v}` },
|
||||
type: {
|
||||
':': (v) => sql`"_type" @> ARRAY[${v.toLocaleLowerCase()}]`,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const makeLevel = new QSplit({
|
||||
default: () => null,
|
||||
fields: {
|
||||
level: qParseNum(sql`("wanikani.subjects"."data" -> 'level')::int`),
|
||||
},
|
||||
})
|
||||
|
||||
f.get<{
|
||||
Querystring: typeof sQuery.type
|
||||
}>(
|
||||
'/q',
|
||||
{
|
||||
schema: {
|
||||
querystring: sQuery.valueOf(),
|
||||
response: {
|
||||
200: sResponse.valueOf(),
|
||||
},
|
||||
},
|
||||
},
|
||||
async (req): Promise<typeof sResponse.type> => {
|
||||
const { q, offset = 0, limit = 5 } = req.query
|
||||
|
||||
if (!q.trim()) {
|
||||
return {
|
||||
result: [],
|
||||
offset,
|
||||
limit,
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
const entryCond = makeEntry.parse(q)
|
||||
const levelCond = makeLevel.parse(q)
|
||||
|
||||
const [r] = await db.query(sql`
|
||||
WITH cte AS (
|
||||
SELECT DISTINCT ON (unnest, "type")
|
||||
unnest "entry", "type", "priority", "frequency"
|
||||
FROM (
|
||||
SELECT
|
||||
unnest("entry"), *
|
||||
FROM "entry"
|
||||
${
|
||||
levelCond
|
||||
? sql`JOIN "wanikani.subjects" ON
|
||||
"entry"."_type" @> ARRAY["wanikani.subjects"."object"]
|
||||
AND "entry"."entry" @> ARRAY["wanikani.subjects"."data" ->> 'characters']`
|
||||
: sql``
|
||||
}
|
||||
WHERE
|
||||
${entryCond || sql`TRUE`}
|
||||
AND ${levelCond || sql`TRUE`}
|
||||
) t1
|
||||
JOIN "frequency" ON "frequency"."entry" = unnest
|
||||
)
|
||||
|
||||
SELECT
|
||||
(SELECT array_agg(jsonb_build_object(
|
||||
'entry', "entry",
|
||||
'type', "type",
|
||||
'frequency', "frequency"
|
||||
)) FROM (
|
||||
SELECT * FROM cte
|
||||
ORDER BY "priority" DESC, "frequency" DESC
|
||||
${limit > 0 ? sql`LIMIT ${limit}` : sql``}
|
||||
OFFSET ${offset}
|
||||
) t1)||'{}'::jsonb[] "result",
|
||||
${offset}::int "offset",
|
||||
${limit}::int "limit",
|
||||
(SELECT count(*) FROM cte) "count"
|
||||
`)
|
||||
|
||||
return (
|
||||
r || {
|
||||
result: [],
|
||||
offset,
|
||||
limit,
|
||||
count: 0,
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user