.
This commit is contained in:
parent
7d61dd7598
commit
163f2b9fa4
@ -0,0 +1,20 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { buildBooleanFullTextQuery } from "../build-boolean-full-text-query";
|
||||
|
||||
describe("buildBooleanFullTextQuery", () => {
|
||||
test.each([
|
||||
["pr", "+pr*"],
|
||||
["pr-", "+pr*"],
|
||||
["-pr", "+pr*"],
|
||||
["cliente prueba", "+cliente* +prueba*"],
|
||||
["cliente-prueba", "+cliente* +prueba*"],
|
||||
["José Pérez", "+José* +Pérez*"],
|
||||
["++ -- **", ""],
|
||||
["", ""],
|
||||
[" ", ""],
|
||||
['+ - > < ( ) ~ * " @', ""],
|
||||
])("normalizes %p into %p", (input, expected) => {
|
||||
expect(buildBooleanFullTextQuery(input)).toBe(expected);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,53 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { Op, type Sequelize } from "sequelize";
|
||||
|
||||
import { Criteria } from "../critera";
|
||||
import { CriteriaToSequelizeConverter } from "../criteria-to-sequelize-converter";
|
||||
|
||||
const createDatabaseStub = () =>
|
||||
({
|
||||
escape: (value: string) => `'${value.replaceAll("'", "''")}'`,
|
||||
}) as Sequelize;
|
||||
|
||||
describe("CriteriaToSequelizeConverter quick search", () => {
|
||||
test("builds a full-text filter and score for free text search", () => {
|
||||
const converter = new CriteriaToSequelizeConverter();
|
||||
const criteria = Criteria.fromPrimitives([], "name", "asc", 10, 0, "pr-");
|
||||
|
||||
const options = converter.convert(criteria, {
|
||||
searchableFields: ["name", "trade_name"],
|
||||
sortableFields: ["name"],
|
||||
enableFullText: true,
|
||||
database: createDatabaseStub(),
|
||||
strictMode: true,
|
||||
});
|
||||
|
||||
expect(options.attributes).toEqual({
|
||||
include: [[expect.objectContaining({ val: expect.stringContaining("'+pr*'") }), "score"]],
|
||||
});
|
||||
expect(options.order).toEqual([
|
||||
[expect.objectContaining({ val: "score" }), "DESC"],
|
||||
["name", "ASC"],
|
||||
]);
|
||||
expect(options.where).toEqual({
|
||||
[Op.and]: expect.any(Array),
|
||||
});
|
||||
});
|
||||
|
||||
test("omits MATCH, score and score ordering when the normalized search is empty", () => {
|
||||
const converter = new CriteriaToSequelizeConverter();
|
||||
const criteria = Criteria.fromPrimitives([], "name", "asc", 10, 0, "++ -- **");
|
||||
|
||||
const options = converter.convert(criteria, {
|
||||
searchableFields: ["name", "trade_name"],
|
||||
sortableFields: ["name"],
|
||||
enableFullText: true,
|
||||
database: createDatabaseStub(),
|
||||
strictMode: true,
|
||||
});
|
||||
|
||||
expect(options.attributes).toBeUndefined();
|
||||
expect(options.order).toEqual([["name", "ASC"]]);
|
||||
expect(options.where).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,9 @@
|
||||
const FULL_TEXT_TOKEN_PATTERN = /[\p{L}\p{N}]+/gu;
|
||||
|
||||
export function buildBooleanFullTextQuery(search: string): string {
|
||||
if (!search) return "";
|
||||
|
||||
const terms = search.normalize("NFKC").match(FULL_TEXT_TOKEN_PATTERN) ?? [];
|
||||
|
||||
return terms.map((term) => `+${term}*`).join(" ");
|
||||
}
|
||||
@ -7,6 +7,7 @@ import type {
|
||||
CriteriaMappings,
|
||||
ICriteriaToOrmConverter,
|
||||
} from "./types.js";
|
||||
import { buildBooleanFullTextQuery } from "./build-boolean-full-text-query.js";
|
||||
import { appendOrder, normalizeOrder, prependOrder } from "./utils";
|
||||
|
||||
/**
|
||||
@ -66,11 +67,8 @@ export class CriteriaToSequelizeConverter implements ICriteriaToOrmConverter {
|
||||
return;
|
||||
}
|
||||
|
||||
const booleanTerm = term
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.map((word) => `+${word}*`)
|
||||
.join(" ");
|
||||
const booleanTerm = buildBooleanFullTextQuery(term);
|
||||
if (!booleanTerm) return;
|
||||
|
||||
const qualifiedFields = searchableFields.map((field) =>
|
||||
this.qualifyRootColumn(field, fullTextTableAlias)
|
||||
@ -216,7 +214,6 @@ export class CriteriaToSequelizeConverter implements ICriteriaToOrmConverter {
|
||||
return Op.lt;
|
||||
case "LOWER_THAN_OR_EQUAL":
|
||||
return Op.lte;
|
||||
case "EQUALS":
|
||||
default:
|
||||
return Op.eq;
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export * from "./critera";
|
||||
export * from "./build-boolean-full-text-query";
|
||||
export * from "./criteria-from-url-converter";
|
||||
export * from "./criteria-to-sequelize-converter";
|
||||
export * from "./defaults";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user