@@ -71,9 +71,30 @@ export function registerCacheCommands(program: Command, ctx: CliContext) {
7171 if ( typeof cacheConfig === 'object' && cacheConfig !== null ) {
7272 const config = cacheConfig as Record < string , any > ;
7373 Console . info ( chalk . bold . blue ( 'Enabled: ' ) + chalk . white ( config . enabled ? 'Yes' : 'No' ) ) ;
74- Console . info ( chalk . bold . blue ( 'TTL: ' ) + chalk . white ( config . ttl || 'N/A' ) ) ;
75- Console . info ( chalk . bold . blue ( 'Max Size: ' ) + chalk . white ( config . max_size || 'N/A' ) ) ;
76- Console . info ( chalk . bold . blue ( 'Strategy: ' ) + chalk . white ( config . strategy || 'N/A' ) ) ;
74+ Console . info ( chalk . bold . blue ( 'Table: ' ) + chalk . white ( config . table || 'N/A' ) ) ;
75+ Console . info ( chalk . bold . blue ( 'Schema: ' ) + chalk . white ( config . schema || 'N/A' ) ) ;
76+ Console . info ( chalk . bold . blue ( 'Schedule: ' ) + chalk . white ( config . schedule || 'N/A' ) ) ;
77+ if ( Array . isArray ( config [ 'primary-key' ] ) ) {
78+ Console . info ( chalk . bold . blue ( 'Primary Key: ' ) + chalk . white ( config [ 'primary-key' ] . join ( ', ' ) ) ) ;
79+ }
80+ if ( config . cursor ) {
81+ Console . info (
82+ chalk . bold . blue ( 'Cursor: ' ) +
83+ chalk . white ( `${ config . cursor . column || 'N/A' } (${ config . cursor . type || 'unknown' } )` )
84+ ) ;
85+ }
86+ if ( config [ 'rollback-window' ] ) {
87+ Console . info ( chalk . bold . blue ( 'Rollback Window: ' ) + chalk . white ( config [ 'rollback-window' ] ) ) ;
88+ }
89+ if ( config . retention ) {
90+ Console . info ( chalk . bold . blue ( 'Retention: ' ) + chalk . white ( JSON . stringify ( config . retention ) ) ) ;
91+ }
92+ if ( config [ 'delete-handling' ] ) {
93+ Console . info ( chalk . bold . blue ( 'Delete Handling: ' ) + chalk . white ( config [ 'delete-handling' ] ) ) ;
94+ }
95+ if ( config [ 'template-file' ] ) {
96+ Console . info ( chalk . bold . blue ( 'Template File: ' ) + chalk . white ( config [ 'template-file' ] ) ) ;
97+ }
7798 } else {
7899 Console . info ( chalk . gray ( 'No cache configuration found' ) ) ;
79100 }
@@ -89,16 +110,32 @@ export function registerCacheCommands(program: Command, ctx: CliContext) {
89110 . command ( 'update <path>' )
90111 . description ( 'Update cache configuration' )
91112 . option ( '-e, --enabled <enabled>' , 'Enable/disable caching (true/false)' )
92- . option ( '-t, --ttl <ttl>' , 'Cache TTL in seconds' )
93- . option ( '-s, --max-size <size>' , 'Maximum cache size' )
94- . option ( '--strategy <strategy>' , 'Cache strategy (lru, ttl, etc.)' )
113+ . option ( '--table <table>' , 'Cache table name' )
114+ . option ( '--schema <schema>' , 'Cache schema name' )
115+ . option ( '--schedule <cron>' , 'Cache refresh schedule or interval string' )
116+ . option ( '--primary-key <columns...>' , 'Primary key columns (space separated)' )
117+ . option ( '--cursor-column <column>' , 'Cursor column name' )
118+ . option ( '--cursor-type <type>' , 'Cursor data type' )
119+ . option ( '--rollback-window <duration>' , 'Rollback window (e.g. 6h)' )
120+ . option ( '--retention-keep <count>' , 'Number of snapshots to keep' )
121+ . option ( '--retention-age <duration>' , 'Max snapshot age (e.g. 7d)' )
122+ . option ( '--delete-handling <mode>' , 'Delete handling strategy' )
123+ . option ( '--template-file <path>' , 'Cache template SQL file' )
95124 . option ( '-f, --file <file>' , 'JSON file containing cache configuration' )
96125 . option ( '--stdin' , 'Read cache configuration from stdin' )
97126 . action ( async ( path : string , options : {
98127 enabled ?: string ;
99- ttl ?: string ;
100- maxSize ?: string ;
101- strategy ?: string ;
128+ table ?: string ;
129+ schema ?: string ;
130+ schedule ?: string ;
131+ primaryKey ?: string [ ] ;
132+ cursorColumn ?: string ;
133+ cursorType ?: string ;
134+ rollbackWindow ?: string ;
135+ retentionKeep ?: string ;
136+ retentionAge ?: string ;
137+ deleteHandling ?: string ;
138+ templateFile ?: string ;
102139 file ?: string ;
103140 stdin ?: boolean ;
104141 } ) => {
@@ -138,14 +175,46 @@ export function registerCacheCommands(program: Command, ctx: CliContext) {
138175 if ( options . enabled !== undefined ) {
139176 cacheConfig . enabled = options . enabled === 'true' ;
140177 }
141- if ( options . ttl !== undefined ) {
142- cacheConfig . ttl = parseInt ( options . ttl ) ;
178+ if ( options . table ) {
179+ cacheConfig . table = options . table ;
180+ }
181+ if ( options . schema ) {
182+ cacheConfig . schema = options . schema ;
183+ }
184+ if ( options . schedule ) {
185+ cacheConfig . schedule = options . schedule ;
186+ }
187+ if ( options . primaryKey && options . primaryKey . length > 0 ) {
188+ cacheConfig [ 'primary-key' ] = options . primaryKey ;
189+ }
190+ if ( ( options . cursorColumn && ! options . cursorType ) || ( ! options . cursorColumn && options . cursorType ) ) {
191+ Console . error ( 'Both --cursor-column and --cursor-type must be provided together' ) ;
192+ process . exitCode = 1 ;
193+ return ;
194+ }
195+ if ( options . cursorColumn && options . cursorType ) {
196+ cacheConfig . cursor = {
197+ column : options . cursorColumn ,
198+ type : options . cursorType ,
199+ } ;
200+ }
201+ if ( options . rollbackWindow ) {
202+ cacheConfig [ 'rollback-window' ] = options . rollbackWindow ;
203+ }
204+ if ( options . retentionKeep || options . retentionAge ) {
205+ cacheConfig . retention = { } ;
206+ if ( options . retentionKeep ) {
207+ cacheConfig . retention [ 'keep-last-snapshots' ] = Number ( options . retentionKeep ) ;
208+ }
209+ if ( options . retentionAge ) {
210+ cacheConfig . retention [ 'max-snapshot-age' ] = options . retentionAge ;
211+ }
143212 }
144- if ( options . maxSize !== undefined ) {
145- cacheConfig . max_size = parseInt ( options . maxSize ) ;
213+ if ( options . deleteHandling ) {
214+ cacheConfig [ 'delete-handling' ] = options . deleteHandling ;
146215 }
147- if ( options . strategy !== undefined ) {
148- cacheConfig . strategy = options . strategy ;
216+ if ( options . templateFile ) {
217+ cacheConfig [ 'template-file' ] = options . templateFile ;
149218 }
150219
151220 if ( Object . keys ( cacheConfig ) . length === 0 ) {
@@ -176,14 +245,14 @@ export function registerCacheCommands(program: Command, ctx: CliContext) {
176245 const endpointUrl = buildEndpointUrl ( path , 'cache/template' ) ;
177246 const response = await ctx . client . get ( endpointUrl ) ;
178247 spinner . succeed ( chalk . green ( `✓ Cache template for ${ path } retrieved` ) ) ;
179- const template = response . data ;
248+ const template = typeof response . data === 'string' ? response . data : response . data ?. template ;
180249
181250 if ( ctx . config . output === 'json' ) {
182- renderJson ( template , ctx . config . jsonStyle ) ;
251+ renderJson ( { template : template ?? '' } , ctx . config . jsonStyle ) ;
183252 } else {
184253 Console . info ( chalk . cyan ( `\n📄 Cache Template: ${ path } ` ) ) ;
185254 Console . info ( chalk . gray ( '═' . repeat ( 60 ) ) ) ;
186- Console . info ( chalk . white ( template ) ) ;
255+ Console . info ( chalk . white ( template ?? '' ) ) ;
187256 }
188257 } catch ( error ) {
189258 spinner . fail ( chalk . red ( `✗ Failed to fetch cache template for ${ path } ` ) ) ;
@@ -256,23 +325,65 @@ export function registerCacheCommands(program: Command, ctx: CliContext) {
256325 const result = response . data ;
257326
258327 if ( ctx . config . output === 'json' ) {
259- renderJson ( result , ctx . config . jsonStyle ) ;
328+ renderJson ( result || { success : true } , ctx . config . jsonStyle ) ;
260329 } else {
261330 Console . info ( chalk . cyan ( `\n🔄 Cache Refresh: ${ path } ` ) ) ;
262331 Console . info ( chalk . gray ( '═' . repeat ( 60 ) ) ) ;
263332 Console . info ( chalk . green ( '✓ Cache refreshed successfully' ) ) ;
264-
265- if ( result . entries_cleared !== undefined ) {
266- Console . info ( chalk . blue ( `Entries cleared: ${ result . entries_cleared } ` ) ) ;
267- }
268- if ( result . cache_size !== undefined ) {
269- Console . info ( chalk . blue ( `New cache size: ${ result . cache_size } ` ) ) ;
270- }
271333 }
272334 } catch ( error ) {
273335 spinner . fail ( chalk . red ( `✗ Failed to refresh cache for ${ path } ` ) ) ;
274336 handleError ( error , ctx . config ) ;
275337 process . exitCode = 1 ;
276338 }
277339 } ) ;
340+
341+ cache
342+ . command ( 'gc <path>' )
343+ . description ( 'Run DuckLake garbage collection for endpoint cache' )
344+ . action ( async ( path : string ) => {
345+ const spinner = Console . spinner ( `Running cache GC for ${ path } ...` ) ;
346+ try {
347+ const endpointUrl = buildEndpointUrl ( path , 'cache/gc' ) ;
348+ await ctx . client . post ( endpointUrl ) ;
349+ spinner . succeed ( chalk . green ( `✓ Cache GC triggered for ${ path } ` ) ) ;
350+ } catch ( error ) {
351+ spinner . fail ( chalk . red ( `✗ Failed to run cache GC for ${ path } ` ) ) ;
352+ handleError ( error , ctx . config ) ;
353+ process . exitCode = 1 ;
354+ }
355+ } ) ;
356+
357+ cache
358+ . command ( 'audit <path>' )
359+ . description ( 'Show DuckLake audit log entries for an endpoint' )
360+ . action ( async ( path : string ) => {
361+ const spinner = Console . spinner ( `Fetching cache audit for ${ path } ...` ) ;
362+ try {
363+ const endpointUrl = buildEndpointUrl ( path , 'cache/audit' ) ;
364+ const response = await ctx . client . get ( endpointUrl ) ;
365+ spinner . succeed ( chalk . green ( `✓ Cache audit for ${ path } retrieved` ) ) ;
366+ renderJson ( response . data , ctx . config . jsonStyle ) ;
367+ } catch ( error ) {
368+ spinner . fail ( chalk . red ( `✗ Failed to fetch cache audit for ${ path } ` ) ) ;
369+ handleError ( error , ctx . config ) ;
370+ process . exitCode = 1 ;
371+ }
372+ } ) ;
373+
374+ cache
375+ . command ( 'audit-all' )
376+ . description ( 'Show DuckLake audit log across all caches' )
377+ . action ( async ( ) => {
378+ const spinner = Console . spinner ( 'Fetching cache audit log...' ) ;
379+ try {
380+ const response = await ctx . client . get ( '/api/v1/_config/cache/audit' ) ;
381+ spinner . succeed ( chalk . green ( '✓ Cache audit log retrieved' ) ) ;
382+ renderJson ( response . data , ctx . config . jsonStyle ) ;
383+ } catch ( error ) {
384+ spinner . fail ( chalk . red ( '✗ Failed to fetch cache audit log' ) ) ;
385+ handleError ( error , ctx . config ) ;
386+ process . exitCode = 1 ;
387+ }
388+ } ) ;
278389}
0 commit comments