# @imqueue/pg-cache 5.0.6 · API reference

Source: https://imqueue.org/api/pg-cache/latest/
Published: 2026-08-04
Author: @imqueue maintainers (https://github.com/imqueue)
Package: @imqueue/pg-cache 5.0.6 — generated reference, not hand-written

PostgreSQL-managed cache on Redis for `@imqueue` service methods: results are memoised, and PostgreSQL itself says when to drop them.

Decorate the service class with [PgCache()](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcache/), then mark cached methods with [cacheWith()](https://imqueue.org/api/pg-cache/latest/pg-cache.cachewith/) or [cacheBy()](https://imqueue.org/api/pg-cache/latest/pg-cache.cacheby/) to declare which tables they depend on.

## Remarks

The point is invalidation that is neither a guessed TTL nor a manual `del()` call. [PgCache()](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcache/) installs a change-notify trigger on each declared table and subscribes to one LISTEN/NOTIFY channel per table; when a row changes, the entries tagged with that table are dropped. So an entry lives exactly as long as the data behind it is unchanged.

Two things to know. The triggers and the subscription are established in `start()`, so a service that never starts is never cached. And a [ChannelFilter](https://imqueue.org/api/pg-cache/latest/pg-cache.channelfilter/) given as an array of [ChannelOperation](https://imqueue.org/api/pg-cache/latest/pg-cache.channeloperation/) is an EXCLUSION list — the operations named in it do not invalidate — which reads the opposite way round from how it looks.

## Example


```typescript
import { PgCache, cacheWith } from '@imqueue/pg-cache';

@PgCache({
    postgres: process.env.DB_URL!,
    redis: { host: 'localhost', port: 6379 },
})
class UserService extends IMQService {
    @cacheWith({ channels: ['users'] })
    public async list(): Promise<User[]> {
        return this.db.query('SELECT * FROM users');
    }
}
```

## Enumerations


| Enumeration | Description |
| --- | --- |
| [ChannelOperation](https://imqueue.org/api/pg-cache/latest/pg-cache.channeloperation/) | The row-level operation that produced a change notification. Matches the PostgreSQL trigger's `TG_OP`. |


## Functions


| Function | Description |
| --- | --- |
| [cacheBy(model, options)](https://imqueue.org/api/pg-cache/latest/pg-cache.cacheby/) | Decorator factory `@cacheBy`(Model, CacheByOptions) This decorator should be used on a service methods, to set the caching rules for a method. Caching rules within this decorator are defined by a passed model, which is treated as a root model of the call and it analyzes cache invalidation based on passed runtime fields arguments, which prevents unnecessary cache invalidations. So it is more intellectual way to invalidate cache instead of any changes on described list of tables. |
| [cacheWith(options)](https://imqueue.org/api/pg-cache/latest/pg-cache.cachewith/) | Decorator factory `@cacheWith`(CacheWithOptions) This decorator should be used on a service methods, to set the caching rules for a method. |
| [channelsOf(model, fields, tables)](https://imqueue.org/api/pg-cache/latest/pg-cache.channelsof/) | Retrieves table names as channels from the given model and filter them by a given fields map, if passed. Returns result as list of table names. |
| [declaringPrototype(instance, methodName)](https://imqueue.org/api/pg-cache/latest/pg-cache.declaringprototype/) | Walks up from a constructed instance to the prototype that actually declares the given method, mirroring legacy decoration where the decorator target is the declaring prototype. Falls back to the instance's own prototype. |
| [envBool(name, defaultValue)](https://imqueue.org/api/pg-cache/latest/pg-cache.envbool/) | Reads a boolean environment variable, accepting the human-friendly spellings 1/true/yes/on and 0/false/no/off (case-insensitive). The previous `!!+value` idiom parsed values like `true` as NaN, i.e. `false`. |
| [fetchError(logger, err, key, decorator)](https://imqueue.org/api/pg-cache/latest/pg-cache.fetcherror/) | Reports a failed cache read at warning level. The caller then falls through to the real method, so a read failure costs latency rather than correctness. |
| [initError(logger, className, methodName, decorator)](https://imqueue.org/api/pg-cache/latest/pg-cache.initerror/) | Reports that a cached method ran before the cache existed — the service was decorated but `start()` has not completed, so there is nothing to read or write. The method still executes; it is simply not cached. |
| [isStandardDecorator(context)](https://imqueue.org/api/pg-cache/latest/pg-cache.isstandarddecorator/) | Returns true if the decorator was invoked in standard (TC39) mode, i.e. its second argument is a decorator context object carrying a `kind`. |
| [makeChannel(name, method, options)](https://imqueue.org/api/pg-cache/latest/pg-cache.makechannel/) | Makes channel entry from a given channel name, class method name and options. |
| [PgCache(options)](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcache/) | Class decorator turning an `@imqueue` service into a PostgreSQL-invalidated cache: method results are memoised in redis, and PostgreSQL itself tells the service when to drop them. It installs a change-notify trigger on every table the service's [cacheWith()](https://imqueue.org/api/pg-cache/latest/pg-cache.cachewith/) and [cacheBy()](https://imqueue.org/api/pg-cache/latest/pg-cache.cacheby/) decorators declare a dependency on, and subscribes to one LISTEN/NOTIFY channel per table. When a row changes, the matching cached results are invalidated by tag — so a cache entry lives exactly as long as the data behind it is unchanged, rather than for a guessed TTL. ```typescript import { PgCache, cacheWith } from '@imqueue/pg-cache'; @PgCache({ postgres: process.env.DB_URL!, redis: { host: 'localhost', port: 6379 }, }) class UserService extends IMQService { @cacheWith({ channels: ['users'] }) public async list(): Promise<User[]> { ... } } ``` Applied to the class, it wraps `start()`: the subscription and the triggers are established there, after any existing `start()` implementation has run. So the cache is inert until the service is started, and a service that never calls `start()` is never cached. Works both as a standard (TC39) decorator and as a legacy (`experimentalDecorators`) one, matching `@imqueue/rpc`, so it can be applied in either compilation mode. Redis is resolved in order: `options.redisCache`, then `options.redis`, then a `cache` property already on the service. If none is available `start()` throws. |
| [registerChannelsOnce(proto, methodName, register)](https://imqueue.org/api/pg-cache/latest/pg-cache.registerchannelsonce/) | Registers pg-cache channel entries for a method on the given prototype exactly once, even when called from a per-construction initializer. |
| [setError(logger, err, key, decorator)](https://imqueue.org/api/pg-cache/latest/pg-cache.seterror/) | Reports a failed cache write at warning level. Always logs: a write failure matters even when tracing is off. |
| [setInfo(logger, res, key, decorator)](https://imqueue.org/api/pg-cache/latest/pg-cache.setinfo/) | Reports a successful cache write and passes the value straight through, so it can be used inline in a return position. Logs only when [PG\_CACHE\_DEBUG](https://imqueue.org/api/pg-cache/latest/pg-cache.pg_cache_debug/) is on. |


## Interfaces


| Interface | Description |
| --- | --- |
| [CacheByOptions](https://imqueue.org/api/pg-cache/latest/pg-cache.cachebyoptions/) | Options expected by `@cacheBy`() decorator factory |
| [CacheWithOptions](https://imqueue.org/api/pg-cache/latest/pg-cache.cachewithoptions/) | Options for the [cacheWith()](https://imqueue.org/api/pg-cache/latest/pg-cache.cachewith/) method decorator: which tables invalidate the cached result, how long it may live, and the tag it is stored under. |
| [ChannelPayload](https://imqueue.org/api/pg-cache/latest/pg-cache.channelpayload/) | Payload delivered on a table's notification channel by the installed trigger, describing a single row change. |
| [FilteredChannels](https://imqueue.org/api/pg-cache/latest/pg-cache.filteredchannels/) | Map of table name to the filter that decides which of its changes matter, for method decorators that watch several tables with different rules. |
| [ILogger](https://imqueue.org/api/pg-cache/latest/pg-cache.ilogger/) | Minimal logger interface accepted by this package. Structurally compatible with the console object and with `@imqueue` loggers, so any of them can be passed without depending on `@imqueue/core.` |
| [PgCacheable](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcacheable/) | What the [PgCache()](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcache/) decorator adds to the class it is applied to. A decorated service gains these three members, so code inside the service can reach the cache and the subscription directly. |
| [PgCacheChannels](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcachechannels/) | Registry of cached methods keyed by the PostgreSQL notification channel that invalidates them. The key is a table name: the installed trigger uses the table name as its NOTIFY channel, so the two are the same string. |
| [PgCacheOptions](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcacheoptions/) | Options for the [PgCache()](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcache/) class decorator: where PostgreSQL and redis live, and how the change-notify triggers behave. Exactly one of `redis` or `redisCache` must be supplied — `redis` to let the decorator build its own connection, `redisCache` to reuse one the service already owns. |


## Variables


| Variable | Description |
| --- | --- |
| [DEFAULT\_CACHE\_TTL](https://imqueue.org/api/pg-cache/latest/pg-cache.default_cache_ttl/) | Default lifetime of a cached entry, in milliseconds — 24 hours. A TTL is a backstop, not the primary invalidation mechanism: entries are normally dropped by a PostgreSQL change notification long before it expires. It exists so an entry cannot outlive its data indefinitely if a notification is ever missed. |
| [PG\_CACHE\_DEBUG](https://imqueue.org/api/pg-cache/latest/pg-cache.pg_cache_debug/) | Whether verbose cache tracing is on, read once from the `PG_CACHE_DEBUG` environment variable at import time. When enabled, cache saves, fetches and trigger installation are logged at info level. Warnings are logged regardless. Because it is read at import time, changing the variable afterwards has no effect. |
| [PG\_CACHE\_TRIGGER](https://imqueue.org/api/pg-cache/latest/pg-cache.pg_cache_trigger/) | Default PL/pgSQL trigger function installed on every watched table. It builds a JSON payload of the changed row and issues `PG_NOTIFY` on a channel named after the table. The payload shape is [ChannelPayload](https://imqueue.org/api/pg-cache/latest/pg-cache.channelpayload/): timestamp, operation, schema, table and the row itself — `NEW` for inserts and updates, `OLD` for deletes. Column values are read out of `information_schema` and cast to TEXT, so every field arrives as a string regardless of its SQL type. Note PostgreSQL caps a NOTIFY payload at 8000 bytes; a change to a very wide row can exceed that and the notification will be rejected. Override with `PgCacheOptions.triggerDefinition` if the default does not suit — see [PgCacheOptions](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcacheoptions/). |


## Type Aliases


| Type Alias | Description |
| --- | --- |
| [ChannelFilter](https://imqueue.org/api/pg-cache/latest/pg-cache.channelfilter/) | Narrows which changes to a table invalidate a cached method. The two forms behave in OPPOSITE directions, which is easy to get wrong: - A [ChannelOperation](https://imqueue.org/api/pg-cache/latest/pg-cache.channeloperation/) array is an \*\*exclusion\*\* list. Operations named in it do NOT invalidate; everything else does. So `[ChannelOperation.DELETE]` means "invalidate on inserts and updates, ignore deletes" — not "invalidate on deletes". - A [ChannelPayloadFilter](https://imqueue.org/api/pg-cache/latest/pg-cache.channelpayloadfilter/) is an \*\*inclusion\*\* predicate: it invalidates when it returns `true`. Omitting the filter invalidates on every change to the table. |
| [ChannelPayloadFilter](https://imqueue.org/api/pg-cache/latest/pg-cache.channelpayloadfilter/) | Predicate deciding whether one change should invalidate the cached method. Returning `true` invalidates. Unlike the array form of [ChannelFilter](https://imqueue.org/api/pg-cache/latest/pg-cache.channelfilter/), this reads the way you expect — see that type for the inversion. |
| [ClassDecorator](https://imqueue.org/api/pg-cache/latest/pg-cache.classdecorator/) | A dual-mode class decorator: called as `(constructor)` by legacy (`experimentalDecorators`) TypeScript and as `(value, context)` by standard (TC39) decorators. In both forms the first argument is the class, and the result is the class augmented with [PgCacheable](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcacheable/). Supporting both is what lets this package decorate `@imqueue` services compiled in either mode, the same way `@imqueue/rpc` and `@imqueue/core` decorators do. |
| [MethodDecorator](https://imqueue.org/api/pg-cache/latest/pg-cache.methoddecorator/) | A dual-mode method decorator: called as `(target, propertyKey, descriptor)` by legacy (`experimentalDecorators`) TypeScript and as `(value, context)` by standard (TC39) decorators. Use [isStandardDecorator()](https://imqueue.org/api/pg-cache/latest/pg-cache.isstandarddecorator/) on the second argument to tell the two apart. |
| [PgCacheChannel](https://imqueue.org/api/pg-cache/latest/pg-cache.pgcachechannel/) | One registered dependency of a cached method: the method to invalidate, and an optional filter narrowing which changes should trigger it. Position 0 is the decorated method name; position 1 is the filter, or `undefined` to invalidate on every change to the table. |

