Class: RubynCode::Memory::Search

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyn_code/memory/search.rb

Overview

Searches memories using SQLite FTS5 full-text search and standard queries. Search methods automatically increment access_count and update last_accessed_at on returned records, reinforcing frequently-accessed memories against decay; #recent accepts touch: false to opt out for passive reads.

Instance Method Summary collapse

Constructor Details

#initialize(db, project_path:) ⇒ Search

Returns a new instance of Search.

Parameters:

  • db (DB::Connection)

    database connection

  • project_path (String)

    scoping path for searches



16
17
18
19
# File 'lib/rubyn_code/memory/search.rb', line 16

def initialize(db, project_path:)
  @db = db
  @project_path = project_path
end

Instance Method Details

#by_category(category, limit: 10) ⇒ Array<MemoryRecord>

Returns memories filtered by category.

Parameters:

  • category (String)
  • limit (Integer) (defaults to: 10)

    maximum results (default 10)

Returns:



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/rubyn_code/memory/search.rb', line 89

def by_category(category, limit: 10)
  rows = @db.query(<<~SQL, [@project_path, category, limit]).to_a
    SELECT id, project_path, tier, category, content,
           relevance_score, access_count, last_accessed_at,
           expires_at, metadata, created_at
    FROM memories
    WHERE project_path = ?
      AND category = ?
    ORDER BY relevance_score DESC, created_at DESC
    LIMIT ?
  SQL

  records = rows.map { |row| build_record(row) }
  touch_accessed(records)
  records
end

#by_tier(tier, limit: 10) ⇒ Array<MemoryRecord>

Returns memories filtered by tier.

Parameters:

  • tier (String)
  • limit (Integer) (defaults to: 10)

    maximum results (default 10)

Returns:



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rubyn_code/memory/search.rb', line 111

def by_tier(tier, limit: 10)
  rows = @db.query(<<~SQL, [@project_path, tier, limit]).to_a
    SELECT id, project_path, tier, category, content,
           relevance_score, access_count, last_accessed_at,
           expires_at, metadata, created_at
    FROM memories
    WHERE project_path = ?
      AND tier = ?
    ORDER BY relevance_score DESC, created_at DESC
    LIMIT ?
  SQL

  records = rows.map { |row| build_record(row) }
  touch_accessed(records)
  records
end

#recent(limit: 10, touch: true) ⇒ Array<MemoryRecord>

Returns the most recently created memories.

Parameters:

  • limit (Integer) (defaults to: 10)

    maximum results (default 10)

  • touch (Boolean) (defaults to: true)

    whether to record an access on returned records; pass false for passive reads (e.g. prompt assembly) that shouldn’t reinforce memories or issue a write

Returns:



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rubyn_code/memory/search.rb', line 68

def recent(limit: 10, touch: true)
  rows = @db.query(<<~SQL, [@project_path, limit]).to_a
    SELECT id, project_path, tier, category, content,
           relevance_score, access_count, last_accessed_at,
           expires_at, metadata, created_at
    FROM memories
    WHERE project_path = ?
    ORDER BY created_at DESC
    LIMIT ?
  SQL

  records = rows.map { |row| build_record(row) }
  touch_accessed(records) if touch
  records
end

#search(query, tier: nil, category: nil, limit: 10) ⇒ Array<MemoryRecord>

Full-text search across memory content using FTS5.

Parameters:

  • query (String)

    the search query (FTS5 syntax supported)

  • tier (String, nil) (defaults to: nil)

    filter by tier

  • category (String, nil) (defaults to: nil)

    filter by category

  • limit (Integer) (defaults to: 10)

    maximum results (default 10)

Returns:



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/rubyn_code/memory/search.rb', line 28

def search(query, tier: nil, category: nil, limit: 10)
  conditions = ['m.project_path = ?']
  params = [@project_path]

  if tier
    conditions << 'm.tier = ?'
    params << tier
  end

  if category
    conditions << 'm.category = ?'
    params << category
  end

  params << query
  params << limit

  rows = @db.query(<<~SQL, params).to_a
    SELECT m.id, m.project_path, m.tier, m.category, m.content,
           m.relevance_score, m.access_count, m.last_accessed_at,
           m.expires_at, m.metadata, m.created_at
    FROM memories m
    WHERE #{conditions.join(' AND ')}
      AND m.content LIKE '%' || ? || '%'
    ORDER BY m.relevance_score DESC, m.created_at DESC
    LIMIT ?
  SQL

  records = rows.map { |row| build_record(row) }
  touch_accessed(records)
  records
end