@rebasepro/server-mongo 0.21.1 → 0.22.0

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.
@@ -40,11 +40,18 @@ export declare class MongoConditionBuilder {
40
40
  */
41
41
  static buildLogicalConditions(logical: LogicalCondition | undefined): Filter<Document> | undefined;
42
42
  /**
43
- * Build search conditions for text search
43
+ * Build search conditions for text search.
44
+ *
45
+ * Terms are split on whitespace and AND-ed, while the fields are OR-ed
46
+ * within each term: a person typing `sebastian melendez` into a search box
47
+ * means both words, and the two live in different fields, so matching the
48
+ * whole string per field finds nothing. See {@link splitSearchTerms}; the
49
+ * Postgres driver's fallback path answers the same way.
44
50
  *
45
51
  * @param searchString - Text to search for
46
52
  * @param properties - The collection's properties, searched for string fields
47
- * @returns Array of MongoDB filter objects for text search
53
+ * @returns At most one MongoDB filter — callers OR what they get back, which
54
+ * is right across fields and wrong across terms, so the AND is built here
48
55
  */
49
56
  static buildSearchConditions(searchString: string, properties: CollectionConfig["properties"]): Filter<Document>[];
50
57
  /**
package/dist/index.es.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { MongoClient, ObjectId } from "mongodb";
2
2
  import { ANONYMOUS_USER_ID, EntityReference, ListLimitError, getCollectionDataPath, isAnonymousUid, resolveClientListLimit } from "@rebasepro/types";
3
- import { buildPropertyCallbacks, buildSdkData, callbackRefusal, checkOperation, normalizeDriverOrderBy, normalizeEmail, requireCallbackClient, securityRuleToConditions, toCallbackError, toFilterTuples, updateDateAutoValues } from "@rebasepro/common";
3
+ import { assertBeforeQueryIsPostgresOnly, buildPropertyCallbacks, buildSdkData, callbackRefusal, checkOperation, normalizeDriverOrderBy, normalizeEmail, requireCallbackClient, securityRuleToConditions, toCallbackError, toFilterTuples, updateDateAutoValues } from "@rebasepro/common";
4
+ import { mergeDeep, splitSearchTerms } from "@rebasepro/utils";
4
5
  import { ApiError, declaredErrorAnswer, logger } from "@rebasepro/server";
5
- import { mergeDeep } from "@rebasepro/utils";
6
6
  //#region \0rolldown/runtime.js
7
7
  var __defProp = Object.defineProperty;
8
8
  var __exportAll = (all, no_symbols) => {
@@ -177,20 +177,31 @@ var MongoConditionBuilder = class MongoConditionBuilder {
177
177
  return logical.type === "or" ? this.combineConditionsWithOr(parts) : this.combineConditionsWithAnd(parts);
178
178
  }
179
179
  /**
180
- * Build search conditions for text search
180
+ * Build search conditions for text search.
181
+ *
182
+ * Terms are split on whitespace and AND-ed, while the fields are OR-ed
183
+ * within each term: a person typing `sebastian melendez` into a search box
184
+ * means both words, and the two live in different fields, so matching the
185
+ * whole string per field finds nothing. See {@link splitSearchTerms}; the
186
+ * Postgres driver's fallback path answers the same way.
181
187
  *
182
188
  * @param searchString - Text to search for
183
189
  * @param properties - The collection's properties, searched for string fields
184
- * @returns Array of MongoDB filter objects for text search
190
+ * @returns At most one MongoDB filter — callers OR what they get back, which
191
+ * is right across fields and wrong across terms, so the AND is built here
185
192
  */
186
193
  static buildSearchConditions(searchString, properties) {
187
194
  if (!searchString) return [];
188
- const orConditions = [];
189
- const escapedSearch = escapeRegExp$1(searchString);
190
- const searchRegex = new RegExp(escapedSearch, "i");
191
- for (const [key, prop] of Object.entries(properties)) if (prop?.type === "string" || typeof prop === "string") orConditions.push({ [key]: { $regex: searchRegex } });
192
- if (orConditions.length === 0) return [{ $text: { $search: searchString } }];
193
- return orConditions;
195
+ const searchableFields = [];
196
+ for (const [key, prop] of Object.entries(properties)) if (prop?.type === "string" || typeof prop === "string") searchableFields.push(key);
197
+ if (searchableFields.length === 0) return [{ $text: { $search: searchString } }];
198
+ const terms = splitSearchTerms(searchString);
199
+ const perTerm = (terms.length > 0 ? terms : [searchString]).map((term) => {
200
+ const regex = new RegExp(escapeRegExp$1(term), "i");
201
+ return this.combineConditionsWithOr(searchableFields.map((field) => ({ [field]: { $regex: regex } })));
202
+ });
203
+ const combined = this.combineConditionsWithAnd(perTerm);
204
+ return combined ? [combined] : [];
194
205
  }
195
206
  /**
196
207
  * Combine multiple conditions with AND operator
@@ -2976,7 +2987,10 @@ function createMongoBootstrapper(mongoConfig) {
2976
2987
  async initializeDriver(config) {
2977
2988
  const { collections } = config;
2978
2989
  const registry = new MongoCollectionRegistry();
2979
- if (collections) collections.forEach((collection) => registry.register(collection));
2990
+ if (collections) {
2991
+ assertBeforeQueryIsPostgresOnly(collections);
2992
+ collections.forEach((collection) => registry.register(collection));
2993
+ }
2980
2994
  const db = mongoConfig.connection;
2981
2995
  const client = mongoConfig.client;
2982
2996
  try {