1/*  File:    redis/xtrim.pl
    2    Author:  Roy Ratcliffe
    3    Created: Jul  7 2026
    4    Purpose: Redis XTRIM command wrapper for Prolog
    5
    6Copyright (c) 2026, Roy Ratcliffe, Northumberland, United Kingdom
    7
    8Permission is hereby granted, free of charge,  to any person obtaining a
    9copy  of  this  software  and    associated   documentation  files  (the
   10"Software"), to deal in  the   Software  without  restriction, including
   11without limitation the rights to  use,   copy,  modify,  merge, publish,
   12distribute, sub-license, and/or sell copies  of   the  Software,  and to
   13permit persons to whom the Software is   furnished  to do so, subject to
   14the following conditions:
   15
   16    The above copyright notice and this permission notice shall be
   17    included in all copies or substantial portions of the Software.
   18
   19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT  WARRANTY OF ANY KIND, EXPRESS
   20OR  IMPLIED,  INCLUDING  BUT  NOT   LIMITED    TO   THE   WARRANTIES  OF
   21MERCHANTABILITY, FITNESS FOR A PARTICULAR   PURPOSE AND NONINFRINGEMENT.
   22IN NO EVENT SHALL THE AUTHORS  OR   COPYRIGHT  HOLDERS BE LIABLE FOR ANY
   23CLAIM, DAMAGES OR OTHER LIABILITY,  WHETHER   IN  AN ACTION OF CONTRACT,
   24TORT OR OTHERWISE, ARISING FROM,  OUT  OF   OR  IN  CONNECTION  WITH THE
   25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   26
   27*/
   28
   29:- module(redis_xtrim,
   30          [ xtrim_using_entry_id/4 % +Redis, +Key, +Id, +Options
   31          , xtrim_window_minid/3   % +Id, -MinId, +Options
   32          ]).   33:- autoload(library(option), [option/3]).   34:- autoload(library(redis), [redis/2]).   35:- use_module(library(settings), [setting/4, setting/2]).   36
   37:- setting(window, number, env('REDIS_XTRIM_DEFAULT_WINDOW', 5),
   38    'Default window for trimming Redis stream entries (in seconds)').

Redis XTRIM command wrapper

This module provides predicates for interacting with Redis streams using the XTRIM command. The xtrim_using_entry_id/4 predicate trims a Redis stream based on a specified entry ID and a window of time, while the xtrim_window_minid/3 predicate calculates the minimum ID for trimming based on the provided entry ID and window size.

The default window size for trimming can be configured using the window setting. By default, it is set to 5 seconds, but it can be changed to any valid number of seconds.

Example Usage

Trim a Redis stream using a specific entry ID and window size:

?- xtrim_using_entry_id(Redis, Key, Id, [window(10)]).
author
- Roy Ratcliffe
version
- 1.0
license
- MIT
 xtrim_using_entry_id(+Redis, +Key, +Id, +Options) is det
Trim the Redis stream identified by Key to remove entries older than the specified Id as the upper bound and a window of time defined by the window/1 option. The Id is expected to be in the format "Millis-Sequence", where Millis is the timestamp in milliseconds. The window size can be specified in Options, and if not provided, the default window size from the window setting will be used.
Arguments:
Redis- The Redis connection.
Key- The Redis stream key to trim.
Id- The ID of the entry to use as the minimum for trimming.
Options- A list of options for trimming, including the window size.
   78xtrim_using_entry_id(Redis, Key, Id, Options) :-
   79    xtrim_window_minid(Id, MinId, Options),
   80    redis(Redis, xtrim(Key, minid, ~, MinId)).
 xtrim_window_minid(+Id, -MinId, +Options) is det
Calculate the minimum ID for trimming based on the provided entry ID and the window/1 option. The MinId is calculated by subtracting the window size (in seconds) from the timestamp part of the provided Id. The resulting MinId is formatted as "Millis-0" to be used for trimming the Redis stream.
Arguments:
Id- The ID of the entry to use as the minimum for trimming.
MinId- The calculated minimum ID for trimming, formatted as "Millis-0".
Options- A list of options for trimming, including the window size.
   94xtrim_window_minid(Id, MinId, Options) :-
   95    % Ignore the sequence number in the entry ID and only use the timestamp for
   96    % trimming. The entry ID atom is expected to be in the format
   97    % "Millis-Sequence", where Millis is the timestamp in milliseconds.
   98    atomic_list_concat([Stamp0, _], -, Id),
   99    atom_number(Stamp0, Stamp1),
  100    setting(window, DefaultWindow),
  101    option(window(Window), Options, DefaultWindow),
  102    % Assume that the Stamp is always a big number: the epoch in
  103    % milliseconds. The window is in seconds, so multiply by 1000 to
  104    % convert to milliseconds.
  105    Stamp is ceiling(Stamp1 - (Window * 1000)),
  106    format(atom(MinId), '~w-0', [Stamp])