metal-orm 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -6
- package/dist/index.cjs +288 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +140 -13
- package/dist/index.d.ts +140 -13
- package/dist/index.js +292 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
- package/src/cache/adapters/keyv-cache-adapter.ts +5 -0
- package/src/cache/adapters/memory-cache-adapter.ts +5 -0
- package/src/cache/adapters/redis-cache-adapter.ts +233 -0
- package/src/cache/cache-interfaces.ts +11 -0
- package/src/cache/index.ts +2 -0
- package/src/core/ast/expression-builders.ts +62 -55
- package/src/dto/execute-filtered-paged.ts +206 -0
- package/src/dto/index.ts +40 -31
package/README.md
CHANGED
|
@@ -110,8 +110,10 @@ Full docs live in the `docs/` folder:
|
|
|
110
110
|
- **Table-valued functions**: use the new `tvf(key, …)` helper when you want portable intents such as `ARRAY_UNNEST`, letting the dialects’ `TableFunctionStrategy` renderers emit dialect-specific syntax (`LATERAL`/`WITH ORDINALITY`, alias validation, quoting, etc.). `fnTable()` remains available as the raw escape hatch when you need to emit a specific SQL function directly.
|
|
111
111
|
- **String helpers**: `lower`, `upper`, `trim`, `ltrim/rtrim`, `concat/concatWs`, `substr/left/right`, `position/instr/locate`, `replace`, `repeat`, `lpad/rpad`, `space`, and more with dialect-aware rendering.
|
|
112
112
|
- **Set operations**: `union`, `unionAll`, `intersect`, `except` across all dialects (ORDER/LIMIT apply to the combined result; hydration is disabled for compound queries so rows are returned as-is without collapsing duplicates).
|
|
113
|
-
- **Expression builders**: `eq`, `and`, `or`, `between`, `inList`, `exists`, `jsonPath`, `caseWhen`, window functions like `rowNumber`, `rank`, `lag`, `lead`, etc., all backed by typed AST nodes.
|
|
114
|
-
- **
|
|
113
|
+
- **Expression builders**: `eq`, `and`, `or`, `between`, `inList`, `exists`, `jsonPath`, `caseWhen`, window functions like `rowNumber`, `rank`, `lag`, `lead`, etc., all backed by typed AST nodes.
|
|
114
|
+
- **Operator safety**: scalar operators (`eq`, `neq`, `gt`, `gte`, `lt`, `lte`) are for single values; for arrays, use `inList`/`notInList`.
|
|
115
|
+
- Migration example: `where(eq(tipoAcao.columns.codigo, codigos))` -> `where(inList(tipoAcao.columns.codigo, codigos))`.
|
|
116
|
+
- **Relation-aware hydration**: turn flat rows into nested objects (`user.posts`, `user.roles`, etc.) using a hydration plan derived from the AST metadata.
|
|
115
117
|
- **Multi-dialect**: compile once, run on MySQL/MariaDB, PostgreSQL, SQLite, or SQL Server via pluggable dialects.
|
|
116
118
|
- **DML**: type-safe INSERT / UPDATE / DELETE with `RETURNING` where supported.
|
|
117
119
|
|
|
@@ -129,7 +131,7 @@ On top of the query builder, MetalORM ships a focused runtime managed by `Orm` a
|
|
|
129
131
|
- **Lazy, batched relations**: `user.posts.load()`, `user.roles.syncByIds([...])`, etc.
|
|
130
132
|
- **Scoped transactions**: `session.transaction(async s => { ... })` wraps `begin/commit/rollback` on the existing executor; `Orm.transaction` remains available when you want a fresh transactional executor per call.
|
|
131
133
|
- **Identity map**: the same row becomes the same entity instance within a session (see the [Identity map pattern](https://en.wikipedia.org/wiki/Identity_map_pattern)).
|
|
132
|
-
- **Caching**: Flexible caching with `MemoryCacheAdapter` (dev)
|
|
134
|
+
- **Caching**: Flexible caching with `MemoryCacheAdapter` (dev), `KeyvCacheAdapter` (simple production), or `RedisCacheAdapter` (full-featured with tag support). Features human-readable TTL (`'30m'`, `'2h'`), tag-based invalidation, and multi-tenant cache isolation.
|
|
133
135
|
- **Tree Behavior (Nested Set/MPTT)**: hierarchical data with `TreeManager`, `treeQuery()`, and `@Tree` decorators. Efficient O(log n) operations for moves, inserts, and deletes. Supports multi-tree scoping, recovery, and validation.
|
|
134
136
|
- **DTO/OpenAPI helpers**: the `metal-orm/dto` module generates DTOs and OpenAPI schemas, including tree schemas (`TreeNode`, `TreeNodeResult`, threaded trees).
|
|
135
137
|
- **Unit of Work (`OrmSession`)** tracking New/Dirty/Removed entities and relation changes, inspired by the classic [Unit of Work pattern](https://en.wikipedia.org/wiki/wiki/Unit_of_work).
|
|
@@ -193,15 +195,24 @@ Pick the matching dialect (`MySqlDialect`, `SQLiteDialect`, `PostgresDialect`, `
|
|
|
193
195
|
|
|
194
196
|
> Drivers are declared as optional peer dependencies. Install only the ones you actually use in your project.
|
|
195
197
|
|
|
196
|
-
**Optional: Caching
|
|
198
|
+
**Optional: Caching Backends**
|
|
197
199
|
|
|
198
|
-
For production caching
|
|
200
|
+
For production caching, choose based on your needs:
|
|
201
|
+
|
|
202
|
+
| Adapter | Tags | Install | Use Case |
|
|
203
|
+
|---------|------|---------|----------|
|
|
204
|
+
| `RedisCacheAdapter` | ✅ Full support | `npm install ioredis` | Production with tag invalidation |
|
|
205
|
+
| `KeyvCacheAdapter` | ❌ Not supported | `npm install keyv @keyv/redis` | Simple production setups |
|
|
199
206
|
|
|
200
207
|
```bash
|
|
208
|
+
# For full-featured Redis (recommended)
|
|
209
|
+
npm install ioredis
|
|
210
|
+
|
|
211
|
+
# For simple Keyv-based caching
|
|
201
212
|
npm install keyv @keyv/redis
|
|
202
213
|
```
|
|
203
214
|
|
|
204
|
-
>
|
|
215
|
+
> Caching packages are optional peer dependencies. MetalORM includes `MemoryCacheAdapter` for development without external dependencies.
|
|
205
216
|
|
|
206
217
|
### Playground (optional) 🧪
|
|
207
218
|
|
package/dist/index.cjs
CHANGED
|
@@ -89,6 +89,7 @@ __export(index_exports, {
|
|
|
89
89
|
PrimaryKey: () => PrimaryKey,
|
|
90
90
|
PrototypeMaterializationStrategy: () => PrototypeMaterializationStrategy,
|
|
91
91
|
QueryCacheManager: () => QueryCacheManager,
|
|
92
|
+
RedisCacheAdapter: () => RedisCacheAdapter,
|
|
92
93
|
RelationKinds: () => RelationKinds,
|
|
93
94
|
STANDARD_COLUMN_TYPES: () => STANDARD_COLUMN_TYPES,
|
|
94
95
|
SelectQueryBuilder: () => SelectQueryBuilder,
|
|
@@ -202,6 +203,7 @@ __export(index_exports, {
|
|
|
202
203
|
eq: () => eq,
|
|
203
204
|
esel: () => esel,
|
|
204
205
|
exclude: () => exclude,
|
|
206
|
+
executeFilteredPaged: () => executeFilteredPaged,
|
|
205
207
|
executeHydrated: () => executeHydrated,
|
|
206
208
|
executeHydratedPlain: () => executeHydratedPlain,
|
|
207
209
|
executeHydratedPlainWithContexts: () => executeHydratedPlainWithContexts,
|
|
@@ -802,6 +804,11 @@ var toOperandNode = (value) => {
|
|
|
802
804
|
if (isLiteralValue(value)) {
|
|
803
805
|
return toLiteralNode(value);
|
|
804
806
|
}
|
|
807
|
+
if (Array.isArray(value)) {
|
|
808
|
+
throw new Error(
|
|
809
|
+
"Array operands are not supported in scalar comparisons. Use inList/notInList for array matching."
|
|
810
|
+
);
|
|
811
|
+
}
|
|
805
812
|
return columnRefToNode(value);
|
|
806
813
|
};
|
|
807
814
|
var valueToOperand = (value) => {
|
|
@@ -14003,6 +14010,11 @@ function isValidDuration(value) {
|
|
|
14003
14010
|
// src/cache/adapters/memory-cache-adapter.ts
|
|
14004
14011
|
var MemoryCacheAdapter = class {
|
|
14005
14012
|
name = "memory";
|
|
14013
|
+
capabilities = {
|
|
14014
|
+
tags: true,
|
|
14015
|
+
prefix: true,
|
|
14016
|
+
ttl: true
|
|
14017
|
+
};
|
|
14006
14018
|
storage = /* @__PURE__ */ new Map();
|
|
14007
14019
|
tagIndex = /* @__PURE__ */ new Map();
|
|
14008
14020
|
async get(key) {
|
|
@@ -16208,6 +16220,129 @@ function computePaginationMetadata(totalItems, page, pageSize) {
|
|
|
16208
16220
|
};
|
|
16209
16221
|
}
|
|
16210
16222
|
|
|
16223
|
+
// src/dto/execute-filtered-paged.ts
|
|
16224
|
+
var normalizeSortBy = (sortBy) => {
|
|
16225
|
+
if (!sortBy) {
|
|
16226
|
+
return void 0;
|
|
16227
|
+
}
|
|
16228
|
+
const normalized = sortBy.trim();
|
|
16229
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
16230
|
+
};
|
|
16231
|
+
var detectPrimaryKeyName = (table) => {
|
|
16232
|
+
const pk = Object.values(table.columns).find((column) => column.primary);
|
|
16233
|
+
return pk?.name;
|
|
16234
|
+
};
|
|
16235
|
+
var toColumnNode = (table, name) => ({
|
|
16236
|
+
type: "Column",
|
|
16237
|
+
table: table.name,
|
|
16238
|
+
name
|
|
16239
|
+
});
|
|
16240
|
+
var getColumnByName = (table, name) => {
|
|
16241
|
+
return Object.values(table.columns).find((column) => column.name === name);
|
|
16242
|
+
};
|
|
16243
|
+
var resolveSortTermFromAllowed = (sortBy, allowedSortColumns) => {
|
|
16244
|
+
if (!allowedSortColumns) {
|
|
16245
|
+
throw new Error("allowedSortColumns is required when sortBy/defaultSortBy is provided.");
|
|
16246
|
+
}
|
|
16247
|
+
const term = allowedSortColumns[sortBy];
|
|
16248
|
+
if (term) {
|
|
16249
|
+
return term;
|
|
16250
|
+
}
|
|
16251
|
+
const allowedKeys = Object.keys(allowedSortColumns);
|
|
16252
|
+
throw new Error(
|
|
16253
|
+
`Invalid sortBy "${sortBy}". Allowed values: ${allowedKeys.length > 0 ? allowedKeys.join(", ") : "(none)"}.`
|
|
16254
|
+
);
|
|
16255
|
+
};
|
|
16256
|
+
var resolvePrimarySort = (table, sortBy, sortDirection, allowedSortColumns, defaultSortBy, defaultSortDirection) => {
|
|
16257
|
+
const requestedSortBy = normalizeSortBy(sortBy);
|
|
16258
|
+
if (requestedSortBy) {
|
|
16259
|
+
return {
|
|
16260
|
+
term: resolveSortTermFromAllowed(requestedSortBy, allowedSortColumns),
|
|
16261
|
+
direction: sortDirection ?? ORDER_DIRECTIONS.ASC
|
|
16262
|
+
};
|
|
16263
|
+
}
|
|
16264
|
+
const configuredDefaultSortBy = normalizeSortBy(defaultSortBy);
|
|
16265
|
+
if (configuredDefaultSortBy) {
|
|
16266
|
+
return {
|
|
16267
|
+
term: resolveSortTermFromAllowed(configuredDefaultSortBy, allowedSortColumns),
|
|
16268
|
+
direction: defaultSortDirection ?? ORDER_DIRECTIONS.ASC
|
|
16269
|
+
};
|
|
16270
|
+
}
|
|
16271
|
+
const detectedPkName = detectPrimaryKeyName(table);
|
|
16272
|
+
if (detectedPkName) {
|
|
16273
|
+
const detectedPkColumn = getColumnByName(table, detectedPkName);
|
|
16274
|
+
if (detectedPkColumn) {
|
|
16275
|
+
return {
|
|
16276
|
+
term: detectedPkColumn,
|
|
16277
|
+
direction: ORDER_DIRECTIONS.ASC
|
|
16278
|
+
};
|
|
16279
|
+
}
|
|
16280
|
+
}
|
|
16281
|
+
const idColumn = getColumnByName(table, "id");
|
|
16282
|
+
return {
|
|
16283
|
+
term: idColumn ?? toColumnNode(table, "id"),
|
|
16284
|
+
direction: ORDER_DIRECTIONS.ASC
|
|
16285
|
+
};
|
|
16286
|
+
};
|
|
16287
|
+
var resolveTieBreaker = (table, tieBreakerColumn) => {
|
|
16288
|
+
const configuredName = normalizeSortBy(tieBreakerColumn);
|
|
16289
|
+
if (configuredName) {
|
|
16290
|
+
const configuredColumn = getColumnByName(table, configuredName);
|
|
16291
|
+
if (!configuredColumn) {
|
|
16292
|
+
throw new Error(
|
|
16293
|
+
`Invalid tieBreakerColumn "${configuredName}" for table "${table.name}".`
|
|
16294
|
+
);
|
|
16295
|
+
}
|
|
16296
|
+
return configuredColumn;
|
|
16297
|
+
}
|
|
16298
|
+
const idColumn = getColumnByName(table, "id");
|
|
16299
|
+
if (idColumn) {
|
|
16300
|
+
return idColumn;
|
|
16301
|
+
}
|
|
16302
|
+
const detectedPkName = detectPrimaryKeyName(table);
|
|
16303
|
+
if (detectedPkName) {
|
|
16304
|
+
const detectedPkColumn = getColumnByName(table, detectedPkName);
|
|
16305
|
+
if (detectedPkColumn) {
|
|
16306
|
+
return detectedPkColumn;
|
|
16307
|
+
}
|
|
16308
|
+
}
|
|
16309
|
+
return toColumnNode(table, "id");
|
|
16310
|
+
};
|
|
16311
|
+
var extractSortColumnName = (term) => {
|
|
16312
|
+
if (typeof term === "object" && term !== null && "name" in term && typeof term.name === "string") {
|
|
16313
|
+
return term.name;
|
|
16314
|
+
}
|
|
16315
|
+
return void 0;
|
|
16316
|
+
};
|
|
16317
|
+
var executeFilteredPaged = async (options) => {
|
|
16318
|
+
const table = options.qb.getTable();
|
|
16319
|
+
const primarySort = resolvePrimarySort(
|
|
16320
|
+
table,
|
|
16321
|
+
options.sortBy,
|
|
16322
|
+
options.sortDirection,
|
|
16323
|
+
options.allowedSortColumns,
|
|
16324
|
+
options.defaultSortBy,
|
|
16325
|
+
options.defaultSortDirection
|
|
16326
|
+
);
|
|
16327
|
+
const tieBreaker = resolveTieBreaker(table, options.tieBreakerColumn);
|
|
16328
|
+
let qb = applyFilter(
|
|
16329
|
+
options.qb,
|
|
16330
|
+
options.tableOrEntity,
|
|
16331
|
+
options.filters
|
|
16332
|
+
);
|
|
16333
|
+
qb = qb.orderBy(primarySort.term, primarySort.direction);
|
|
16334
|
+
const primarySortColumnName = extractSortColumnName(primarySort.term);
|
|
16335
|
+
const tieBreakerColumnName = extractSortColumnName(tieBreaker);
|
|
16336
|
+
if (primarySortColumnName !== tieBreakerColumnName) {
|
|
16337
|
+
qb = qb.orderBy(tieBreaker, ORDER_DIRECTIONS.ASC);
|
|
16338
|
+
}
|
|
16339
|
+
const result = await qb.executePaged(options.session, {
|
|
16340
|
+
page: options.page,
|
|
16341
|
+
pageSize: options.pageSize
|
|
16342
|
+
});
|
|
16343
|
+
return toPagedResponse(result);
|
|
16344
|
+
};
|
|
16345
|
+
|
|
16211
16346
|
// src/dto/openapi/type-mappings.ts
|
|
16212
16347
|
var IntegerTypeStrategy = class {
|
|
16213
16348
|
types = ["INT", "INTEGER"];
|
|
@@ -18733,6 +18868,11 @@ var KeyvCacheAdapter = class {
|
|
|
18733
18868
|
this.keyv = keyv;
|
|
18734
18869
|
}
|
|
18735
18870
|
name = "keyv";
|
|
18871
|
+
capabilities = {
|
|
18872
|
+
tags: false,
|
|
18873
|
+
prefix: true,
|
|
18874
|
+
ttl: true
|
|
18875
|
+
};
|
|
18736
18876
|
async get(key) {
|
|
18737
18877
|
return this.keyv.get(key);
|
|
18738
18878
|
}
|
|
@@ -18776,6 +18916,152 @@ var KeyvCacheAdapter = class {
|
|
|
18776
18916
|
}
|
|
18777
18917
|
};
|
|
18778
18918
|
|
|
18919
|
+
// src/cache/adapters/redis-cache-adapter.ts
|
|
18920
|
+
var RedisCacheAdapter = class {
|
|
18921
|
+
name = "redis";
|
|
18922
|
+
capabilities = {
|
|
18923
|
+
tags: true,
|
|
18924
|
+
prefix: true,
|
|
18925
|
+
ttl: true
|
|
18926
|
+
};
|
|
18927
|
+
redis;
|
|
18928
|
+
ownsConnection;
|
|
18929
|
+
tagPrefix;
|
|
18930
|
+
/**
|
|
18931
|
+
* Cria um adapter Redis
|
|
18932
|
+
*
|
|
18933
|
+
* @param redis - Instância do ioredis OU opções de conexão
|
|
18934
|
+
* @param options - Opções adicionais
|
|
18935
|
+
* @param options.tagPrefix - Prefixo para chaves de tag (default: 'tag:')
|
|
18936
|
+
*
|
|
18937
|
+
* Exemplos:
|
|
18938
|
+
*
|
|
18939
|
+
* // Com instância existente (recomendado para connection pooling):
|
|
18940
|
+
* const redis = new Redis({ host: 'localhost', port: 6379 });
|
|
18941
|
+
* const adapter = new RedisCacheAdapter(redis);
|
|
18942
|
+
*
|
|
18943
|
+
* // Com opções (adapter gerencia conexão):
|
|
18944
|
+
* const adapter = new RedisCacheAdapter({ host: 'localhost', port: 6379 });
|
|
18945
|
+
*
|
|
18946
|
+
* // Para testes com ioredis-mock:
|
|
18947
|
+
* import Redis from 'ioredis-mock';
|
|
18948
|
+
* const adapter = new RedisCacheAdapter(new Redis());
|
|
18949
|
+
*/
|
|
18950
|
+
constructor(redis, options) {
|
|
18951
|
+
this.tagPrefix = options?.tagPrefix ?? "tag:";
|
|
18952
|
+
if (this.isRedisInstance(redis)) {
|
|
18953
|
+
this.redis = redis;
|
|
18954
|
+
this.ownsConnection = false;
|
|
18955
|
+
} else {
|
|
18956
|
+
this.redis = this.createRedis(redis);
|
|
18957
|
+
this.ownsConnection = true;
|
|
18958
|
+
}
|
|
18959
|
+
}
|
|
18960
|
+
isRedisInstance(obj) {
|
|
18961
|
+
return typeof obj === "object" && obj !== null && "get" in obj && "set" in obj && "del" in obj && typeof obj.get === "function";
|
|
18962
|
+
}
|
|
18963
|
+
createRedis(options) {
|
|
18964
|
+
try {
|
|
18965
|
+
const Redis = require("ioredis");
|
|
18966
|
+
return new Redis(options);
|
|
18967
|
+
} catch {
|
|
18968
|
+
throw new Error(
|
|
18969
|
+
"ioredis is required for RedisCacheAdapter. Install it with: npm install ioredis"
|
|
18970
|
+
);
|
|
18971
|
+
}
|
|
18972
|
+
}
|
|
18973
|
+
async get(key) {
|
|
18974
|
+
const value = await this.redis.get(key);
|
|
18975
|
+
if (value === null) {
|
|
18976
|
+
return void 0;
|
|
18977
|
+
}
|
|
18978
|
+
try {
|
|
18979
|
+
return JSON.parse(value);
|
|
18980
|
+
} catch {
|
|
18981
|
+
return void 0;
|
|
18982
|
+
}
|
|
18983
|
+
}
|
|
18984
|
+
async has(key) {
|
|
18985
|
+
const value = await this.redis.get(key);
|
|
18986
|
+
return value !== null;
|
|
18987
|
+
}
|
|
18988
|
+
async set(key, value, ttlMs, tags) {
|
|
18989
|
+
const serialized = JSON.stringify(value);
|
|
18990
|
+
if (ttlMs) {
|
|
18991
|
+
await this.redis.set(key, serialized, "PX", ttlMs);
|
|
18992
|
+
} else {
|
|
18993
|
+
await this.redis.set(key, serialized);
|
|
18994
|
+
}
|
|
18995
|
+
if (tags && tags.length > 0) {
|
|
18996
|
+
await this.registerTags(key, tags);
|
|
18997
|
+
}
|
|
18998
|
+
}
|
|
18999
|
+
async delete(key) {
|
|
19000
|
+
await this.redis.del(key);
|
|
19001
|
+
}
|
|
19002
|
+
async invalidate(key) {
|
|
19003
|
+
await this.delete(key);
|
|
19004
|
+
}
|
|
19005
|
+
async invalidateTags(tags) {
|
|
19006
|
+
const keysToDelete = /* @__PURE__ */ new Set();
|
|
19007
|
+
for (const tag of tags) {
|
|
19008
|
+
const tagKey = `${this.tagPrefix}${tag}`;
|
|
19009
|
+
const keys = await this.redis.smembers(tagKey);
|
|
19010
|
+
for (const key of keys) {
|
|
19011
|
+
keysToDelete.add(key);
|
|
19012
|
+
}
|
|
19013
|
+
await this.redis.del(tagKey);
|
|
19014
|
+
}
|
|
19015
|
+
if (keysToDelete.size > 0) {
|
|
19016
|
+
await this.redis.del(...Array.from(keysToDelete));
|
|
19017
|
+
}
|
|
19018
|
+
}
|
|
19019
|
+
async invalidatePrefix(prefix) {
|
|
19020
|
+
const keysToDelete = [];
|
|
19021
|
+
let cursor = "0";
|
|
19022
|
+
do {
|
|
19023
|
+
const [nextCursor, keys] = await this.redis.scan(
|
|
19024
|
+
cursor,
|
|
19025
|
+
"MATCH",
|
|
19026
|
+
`${prefix}*`,
|
|
19027
|
+
"COUNT",
|
|
19028
|
+
100
|
|
19029
|
+
);
|
|
19030
|
+
cursor = nextCursor;
|
|
19031
|
+
keysToDelete.push(...keys);
|
|
19032
|
+
} while (cursor !== "0");
|
|
19033
|
+
if (keysToDelete.length > 0) {
|
|
19034
|
+
const batchSize = 1e3;
|
|
19035
|
+
for (let i = 0; i < keysToDelete.length; i += batchSize) {
|
|
19036
|
+
const batch = keysToDelete.slice(i, i + batchSize);
|
|
19037
|
+
await this.redis.del(...batch);
|
|
19038
|
+
}
|
|
19039
|
+
}
|
|
19040
|
+
}
|
|
19041
|
+
async registerTags(key, tags) {
|
|
19042
|
+
for (const tag of tags) {
|
|
19043
|
+
const tagKey = `${this.tagPrefix}${tag}`;
|
|
19044
|
+
await this.redis.sadd(tagKey, key);
|
|
19045
|
+
}
|
|
19046
|
+
}
|
|
19047
|
+
async dispose() {
|
|
19048
|
+
if (this.ownsConnection) {
|
|
19049
|
+
try {
|
|
19050
|
+
await this.redis.quit();
|
|
19051
|
+
} catch {
|
|
19052
|
+
this.redis.disconnect?.();
|
|
19053
|
+
}
|
|
19054
|
+
}
|
|
19055
|
+
}
|
|
19056
|
+
/**
|
|
19057
|
+
* Retorna a instância Redis subjacente
|
|
19058
|
+
* Útil para operações avançadas ou health checks
|
|
19059
|
+
*/
|
|
19060
|
+
getRedis() {
|
|
19061
|
+
return this.redis;
|
|
19062
|
+
}
|
|
19063
|
+
};
|
|
19064
|
+
|
|
18779
19065
|
// src/cache/tag-index.ts
|
|
18780
19066
|
var TagIndex = class {
|
|
18781
19067
|
tagToKeys = /* @__PURE__ */ new Map();
|
|
@@ -18930,6 +19216,7 @@ var TagIndex = class {
|
|
|
18930
19216
|
PrimaryKey,
|
|
18931
19217
|
PrototypeMaterializationStrategy,
|
|
18932
19218
|
QueryCacheManager,
|
|
19219
|
+
RedisCacheAdapter,
|
|
18933
19220
|
RelationKinds,
|
|
18934
19221
|
STANDARD_COLUMN_TYPES,
|
|
18935
19222
|
SelectQueryBuilder,
|
|
@@ -19043,6 +19330,7 @@ var TagIndex = class {
|
|
|
19043
19330
|
eq,
|
|
19044
19331
|
esel,
|
|
19045
19332
|
exclude,
|
|
19333
|
+
executeFilteredPaged,
|
|
19046
19334
|
executeHydrated,
|
|
19047
19335
|
executeHydratedPlain,
|
|
19048
19336
|
executeHydratedPlainWithContexts,
|