@@ -11,16 +11,23 @@ import {
1111import { sql as drizzleSql } from 'drizzle-orm'
1212import { beforeEach , describe , expect , it , vi } from 'vitest'
1313
14- const { mockBuildFilterClause, mockBuildPredicateClause, mockBuildSortClause } = vi . hoisted ( ( ) => ( {
14+ const {
15+ mockBuildFilterClause,
16+ mockBuildPredicateClause,
17+ mockBuildSortClause,
18+ mockEscapeLikePattern,
19+ } = vi . hoisted ( ( ) => ( {
1520 mockBuildFilterClause : vi . fn ( ( ) => ( { type : 'filter' } ) ) ,
1621 mockBuildPredicateClause : vi . fn ( ( ) => ( { type : 'predicate' } ) ) ,
1722 mockBuildSortClause : vi . fn ( ( ) => ( { type : 'sort' } ) ) ,
23+ mockEscapeLikePattern : vi . fn ( ( value : string ) => value ) ,
1824} ) )
1925
2026vi . mock ( '@/lib/table/sql' , ( ) => ( {
2127 buildFilterClause : mockBuildFilterClause ,
2228 buildPredicateClause : mockBuildPredicateClause ,
2329 buildSortClause : mockBuildSortClause ,
30+ escapeLikePattern : mockEscapeLikePattern ,
2431} ) )
2532
2633vi . mock ( 'drizzle-orm' , ( ) => {
@@ -47,6 +54,7 @@ vi.mock('drizzle-orm', () => {
4754} )
4855
4956import {
57+ findMemoryTableRowMatches ,
5058 getMemoryTableDefinition ,
5159 queryMemoryTableRows ,
5260} from '@/lib/virtual-tables/memory-virtual-table.server'
@@ -258,6 +266,60 @@ describe('Memory virtual table', () => {
258266 )
259267 } )
260268
269+ it ( 'finds matching cells in one storage query and preserves filtered sort ordinals' , async ( ) => {
270+ dbChainMockFns . execute . mockResolvedValueOnce ( [
271+ { ordinal : '4' , id : 'memory-1' , column_name : 'transcript' } ,
272+ { ordinal : 7 , id : 'memory-2' , column_name : 'conversation_id' } ,
273+ ] )
274+
275+ await expect (
276+ findMemoryTableRowMatches ( {
277+ workspaceId : 'workspace-1' ,
278+ q : '50%_off' ,
279+ filter : { conversation_id : { $contains : 'customer' } } ,
280+ sort : { updated_at : 'asc' } ,
281+ } )
282+ ) . resolves . toEqual ( {
283+ matches : [
284+ { ordinal : 4 , rowId : 'memory-1' , column : 'transcript' } ,
285+ { ordinal : 7 , rowId : 'memory-2' , column : 'conversation_id' } ,
286+ ] ,
287+ truncated : false ,
288+ } )
289+
290+ expect ( dbChainMockFns . execute ) . toHaveBeenCalledTimes ( 1 )
291+ expect ( mockEscapeLikePattern ) . toHaveBeenCalledWith ( '50%_off' )
292+ expect ( mockBuildFilterClause ) . toHaveBeenCalledWith (
293+ { conversation_id : { $contains : 'customer' } } ,
294+ 'memory_rows' ,
295+ expect . any ( Array )
296+ )
297+ expect ( mockBuildSortClause ) . toHaveBeenCalledWith (
298+ { updated_at : 'asc' } ,
299+ 'memory_rows' ,
300+ expect . any ( Array )
301+ )
302+ const findSqlCall = vi
303+ . mocked ( drizzleSql )
304+ . mock . calls . find ( ( [ strings ] ) => Array . from ( strings ) . join ( '' ) . includes ( 'jsonb_each_text' ) )
305+ expect ( findSqlCall ) . toBeDefined ( )
306+ } )
307+
308+ it ( 'caps storage matches and reports truncation' , async ( ) => {
309+ dbChainMockFns . execute . mockResolvedValueOnce (
310+ Array . from ( { length : 1001 } , ( _ , index ) => ( {
311+ ordinal : index ,
312+ id : `memory-${ index } ` ,
313+ column_name : 'transcript' ,
314+ } ) )
315+ )
316+
317+ const result = await findMemoryTableRowMatches ( { workspaceId : 'workspace-1' , q : 'hello' } )
318+
319+ expect ( result ) . toMatchObject ( { truncated : true } )
320+ expect ( result . matches ) . toHaveLength ( 1000 )
321+ } )
322+
261323 it ( 'returns an empty page' , async ( ) => {
262324 queueTableRows ( schemaMock . memory , [ ] )
263325
0 commit comments