@m1212e/rumble 0.13.2 → 0.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/out/index.cjs CHANGED
@@ -1357,12 +1357,18 @@ function isPostgresDB(db) {
1357
1357
 
1358
1358
  //#endregion
1359
1359
  //#region lib/search.ts
1360
- async function initSearchIfApplicable(db) {
1361
- if (!isPostgresDB(db)) {
1362
- console.info("Database dialect is not compatible with search, skipping search initialization.");
1360
+ async function initSearchIfApplicable(input) {
1361
+ if (!isPostgresDB(input.db)) {
1362
+ console.info("Database dialect is not compatible with search, skipping search initialization. Only PostgreSQL is supported.");
1363
1363
  return;
1364
1364
  }
1365
- await db.execute(drizzle_orm.sql`CREATE EXTENSION IF NOT EXISTS pg_trgm;`);
1365
+ await input.db.execute(drizzle_orm.sql`CREATE EXTENSION IF NOT EXISTS pg_trgm;`);
1366
+ if (input.search?.threshold) {
1367
+ const threshold = Number(input.search.threshold);
1368
+ if (threshold < 0 || threshold > 1) throw new Error(`Search threshold must be between 0 and 1`);
1369
+ const dbName = (await input.db.execute(drizzle_orm.sql`SELECT current_database()`)).rows[0].current_database;
1370
+ await input.db.execute(drizzle_orm.sql.raw(`ALTER DATABASE ${dbName} SET pg_trgm.similarity_threshold = ${threshold};`));
1371
+ }
1366
1372
  }
1367
1373
  /**
1368
1374
  * Performs adjustments to the query args to issue a full text search in case the
@@ -1370,14 +1376,11 @@ async function initSearchIfApplicable(db) {
1370
1376
  */
1371
1377
  function adjustQueryArgsForSearch({ search, args, tableSchema, abilities }) {
1372
1378
  if (search?.enabled && args.search && args.search.length > 0) {
1373
- const columnsToSearch = abilities.query.many.columns ? Object.entries(tableSchema.columns).filter(([key]) => abilities.query.many.columns[key]) : Object.entries(tableSchema.columns);
1379
+ const columnsToSearch = (abilities.query.many.columns ? Object.entries(tableSchema.columns).filter(([key]) => abilities.query.many.columns[key]) : Object.entries(tableSchema.columns)).filter(([key, col]) => isStringLikeSQLTypeString(col.getSQLType()) || isIDLikeSQLTypeString(col.getSQLType()));
1374
1380
  const searchParam = drizzle_orm.sql`${args.search}`;
1375
- const scoring = (table) => (search?.score ?? "sum") === "sum" ? drizzle_orm.sql`(${drizzle_orm.sql.join(columnsToSearch.map(([key]) => {
1376
- return drizzle_orm.sql`COALESCE(similarity(${table[key]}::TEXT, ${searchParam}), 0)`;
1377
- }), drizzle_orm.sql.raw(" + "))})` : drizzle_orm.sql`GREATEST(${drizzle_orm.sql.join(columnsToSearch.map(([key]) => {
1378
- return drizzle_orm.sql`similarity(${table[key]}::TEXT, ${searchParam})`;
1379
- }), drizzle_orm.sql.raw(", "))})`;
1380
- args.extras = { search_score: scoring };
1381
+ args.extras = { search_distance: (table) => drizzle_orm.sql`${drizzle_orm.sql.join(columnsToSearch.map(([key]) => {
1382
+ return drizzle_orm.sql`COALESCE((${table[key]}::TEXT <-> ${searchParam}), 1)`;
1383
+ }), drizzle_orm.sql.raw(" + "))}` };
1381
1384
  const originalOrderBy = (0, es_toolkit.cloneDeep)(args.orderBy);
1382
1385
  args.orderBy = (table) => {
1383
1386
  const argsOrderBySQL = drizzle_orm.sql.join(Object.entries(originalOrderBy ?? {}).map(([key, value]) => {
@@ -1385,12 +1388,12 @@ function adjustQueryArgsForSearch({ search, args, tableSchema, abilities }) {
1385
1388
  else if (value === "desc") return drizzle_orm.sql`${table[key]} DESC`;
1386
1389
  else throw new Error(`Invalid value ${value} for orderBy`);
1387
1390
  }), drizzle_orm.sql.raw(", "));
1388
- const searchSQL = drizzle_orm.sql`search_score DESC`;
1391
+ const searchSQL = drizzle_orm.sql`search_distance ASC`;
1389
1392
  return originalOrderBy ? drizzle_orm.sql.join([argsOrderBySQL, searchSQL], drizzle_orm.sql.raw(", ")) : searchSQL;
1390
1393
  };
1391
- args.where = { AND: [(0, es_toolkit.cloneDeep)(args.where) ?? {}, { RAW: (table) => {
1392
- return drizzle_orm.sql`${scoring(table)} > ${search.threshold ?? .15}`;
1393
- } }] };
1394
+ args.where = { AND: [(0, es_toolkit.cloneDeep)(args.where) ?? {}, { RAW: (table) => drizzle_orm.sql`(${drizzle_orm.sql.join(columnsToSearch.map(([key]) => {
1395
+ return drizzle_orm.sql`${table[key]} % ${searchParam}`;
1396
+ }), drizzle_orm.sql.raw(" OR "))})` }] };
1394
1397
  }
1395
1398
  }
1396
1399
 
@@ -1551,11 +1554,11 @@ const createObjectImplementer = ({ db, search, schemaBuilder, makePubSubInstance
1551
1554
  return acc;
1552
1555
  }, {});
1553
1556
  if (search?.enabled) {
1554
- if (fields.search_score) throw new Error("Reserved field name 'search_score' found on " + tableSchema.tsName + ". If search is enabled, the 'search_score' field is automatically added and cannot be defined manually.");
1555
- fields.search_score = t.float({
1556
- description: "The search score of the object. If a search is provided, this field will be populated with the search score.",
1557
+ if (fields.search_distance) throw new Error("Reserved field name 'search_distance' found on " + tableSchema.tsName + ". If search is enabled, the 'search_distance' field is automatically added and cannot be defined manually.");
1558
+ fields.search_distance = t.float({
1559
+ description: "The search distance of the object. If a search is provided, this field will be populated with the search distance.",
1557
1560
  nullable: true,
1558
- resolve: (parent, args, ctx, info) => parent.search_score
1561
+ resolve: (parent, args, ctx, info) => parent.search_distance
1559
1562
  });
1560
1563
  }
1561
1564
  return {
@@ -1937,7 +1940,7 @@ export const db = drizzle(
1937
1940
  "delete"
1938
1941
  ];
1939
1942
  if (rumbleInput.defaultLimit === void 0) rumbleInput.defaultLimit = 100;
1940
- if (rumbleInput.search?.enabled) initSearchIfApplicable(rumbleInput.db);
1943
+ if (rumbleInput.search?.enabled) initSearchIfApplicable(rumbleInput);
1941
1944
  const abilityBuilder = createAbilityBuilder(rumbleInput);
1942
1945
  const context = createContextFunction({
1943
1946
  ...rumbleInput,