@danielsimonjr/memoryjs 2.7.0 → 2.8.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.
package/dist/index.cjs CHANGED
@@ -21256,6 +21256,27 @@ CREATE INDEX IF NOT EXISTS idx_entities_project_id ON entities(project_id);
21256
21256
  CREATE INDEX IF NOT EXISTS idx_entities_content_hash ON entities(content_hash);
21257
21257
  CREATE INDEX IF NOT EXISTS idx_entities_tags_gin ON entities USING GIN(tags);
21258
21258
 
21259
+ -- v2.8.0 \u2014 generated tsvector column for full-text search.
21260
+ -- name is weighted A (highest), observations B, tags C. PostgreSQL 12+
21261
+ -- supports GENERATED ALWAYS AS ... STORED; the DO block makes the column
21262
+ -- add idempotent on older + newer servers without requiring CREATE OR
21263
+ -- REPLACE semantics on ALTER.
21264
+ DO $$ BEGIN
21265
+ IF NOT EXISTS (
21266
+ SELECT 1 FROM information_schema.columns
21267
+ WHERE table_name = 'entities' AND column_name = 'fts_vector'
21268
+ ) THEN
21269
+ ALTER TABLE entities ADD COLUMN fts_vector tsvector
21270
+ GENERATED ALWAYS AS (
21271
+ setweight(to_tsvector('english', name), 'A') ||
21272
+ setweight(to_tsvector('english', coalesce(array_to_string(observations, ' '), '')), 'B') ||
21273
+ setweight(to_tsvector('english', coalesce(array_to_string(tags, ' '), '')), 'C')
21274
+ ) STORED;
21275
+ END IF;
21276
+ END $$;
21277
+
21278
+ CREATE INDEX IF NOT EXISTS idx_entities_fts_gin ON entities USING GIN(fts_vector);
21279
+
21259
21280
  CREATE TABLE IF NOT EXISTS relations (
21260
21281
  from_name TEXT NOT NULL,
21261
21282
  to_name TEXT NOT NULL,
@@ -21575,6 +21596,38 @@ var PostgreSQLStorage = class {
21575
21596
  hasRelations(entityName) {
21576
21597
  return (this.outgoingRelations.get(entityName)?.length ?? 0) + (this.incomingRelations.get(entityName)?.length ?? 0) > 0;
21577
21598
  }
21599
+ // ==================== Full-text search ====================
21600
+ /**
21601
+ * tsvector-backed full-text search. Uses `plainto_tsquery` so the input is
21602
+ * free-form (no boolean operator syntax required); ranks via `ts_rank` on
21603
+ * the weighted `fts_vector` column (name × A, observations × B, tags × C).
21604
+ *
21605
+ * Results are ordered by descending score and capped at `options.limit`
21606
+ * (default 50). Empty / whitespace-only queries return `[]` without
21607
+ * issuing a SQL call.
21608
+ *
21609
+ * @example
21610
+ * ```typescript
21611
+ * const matches = await storage.fullTextSearch('authentication flow', { limit: 10 });
21612
+ * // → [{ name: 'AuthService', score: 0.62 }, ...]
21613
+ * ```
21614
+ */
21615
+ async fullTextSearch(query, options = {}) {
21616
+ const trimmed = query.trim();
21617
+ if (trimmed.length === 0) return [];
21618
+ await this.initSchema();
21619
+ const pool = await this.getPool();
21620
+ const limit = options.limit ?? 50;
21621
+ const res = await pool.query(
21622
+ `SELECT name, ts_rank(fts_vector, plainto_tsquery('english', $1))::float AS score
21623
+ FROM entities
21624
+ WHERE fts_vector @@ plainto_tsquery('english', $1)
21625
+ ORDER BY score DESC
21626
+ LIMIT $2`,
21627
+ [trimmed, limit]
21628
+ );
21629
+ return res.rows.map((r) => ({ name: r.name, score: Number(r.score) }));
21630
+ }
21578
21631
  // ==================== Utility ====================
21579
21632
  getFilePath() {
21580
21633
  return this.connectionString;